[
  {
    "path": ".editorconfig",
    "content": "﻿## \n## PROJECT:    Mouri Internal Library Essentials\n## FILE:       .editorconfig\n## PURPOSE:    The root .editorconfig file\n## \n## LICENSE:    The MIT License\n## \n## MAINTAINER: MouriNaruto (Kenji.Mouri@outlook.com)\n## \n\nroot = true\n\n[*]\ncharset = utf-8-bom\nend_of_line = crlf\n\n[*.md]\ninsert_final_newline = true\n\n[*.{c,c++,cc,cpp,cxx,h,h++,hh,hpp,hxx,ixx,cppm,ipp,odl,idl,inl,ipp,tlh,tli}]\nindent_style = space\nindent_size = 4\ninsert_final_newline = true\ntrim_trailing_whitespace = true\nvc_generate_documentation_comments = doxygen_slash_star\n\n[*.{cs,csx,vb,vbx,asmx}]\nindent_style = space\nindent_size = 4\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.{js,json,xml,toml,xaml}]\nindent_style = space\nindent_size = 2\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.rc]\ncharset = utf-16le\n\n[*.inf]\ncharset = utf-16le\n\n[*.bat]\ncharset = utf-8\ninsert_final_newline = true\n\n[*.sh]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\n\n[*.{asm,inc,s,nasm}]\ncharset = utf-8\nindent_style = space\nindent_size = 4\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "patreon: MouriNaruto\ncustom: [\n  \"https://paypal.me/MouriNaruto\",\n  \"https://afdian.net/a/MouriNaruto\",\n  \"https://github.com/MouriNaruto/MouriNaruto/tree/main/Sponsor#alipay\",\n  \"https://github.com/MouriNaruto/MouriNaruto/tree/main/Sponsor#wechat\"\n]\n"
  },
  {
    "path": ".github/workflows/BuildBinaries.yml",
    "content": "﻿name: Build Binaries\n\non:\n  push:\n    paths-ignore:\n      - '.github/*'\n      - '*.md'\n  pull_request:\n    paths-ignore:\n      - '.github/*'\n      - '*.md'\n\njobs:\n  build:\n    runs-on: windows-latest\n    env:\n      POWERSHELL_TELEMETRY_OPTOUT: 1\n    steps:\n    - uses: actions/checkout@v4\n      with:\n        submodules: 'recursive'\n    - uses: microsoft/setup-msbuild@v2\n    - name: Clear local NuGet cache (workaround for failed restores on windows-latest)\n      run: dotnet nuget locals all --clear\n    - name: Build\n      run: msbuild -m BuildAllTargets.proj\n    - name: Prepare artifacts\n      run: rm Output\\Binaries\\* -vb -Recurse -Force -Include *.exp, *.idb, *.ilk, *.iobj, *.ipdb, *.lastbuildstate, *.lib, *.obj, *.res, *.tlog\n    - uses: actions/upload-artifact@v4\n      with:\n        name: NanaRun_CI_Build\n        path: Output\\Binaries\n"
  },
  {
    "path": ".gitignore",
    "content": "## \n## PROJECT:    Mouri Internal Library Essentials\n## FILE:       .gitignore\n## PURPOSE:    The root .gitignore file for Visual Studio C++ Project\n## \n## LICENSE:    The MIT License\n## \n## MAINTAINER: MouriNaruto (Kenji.Mouri@outlook.com)\n## \n\n##\n## Ignore Mile.Project specific temporary files, build results,\n## and files generated by popular Visual Studio add-ons.\n## \nOutput/\n\n##\n## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Mono auto generated files\nmono_crash.*\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\n[Ww][Ii][Nn]32/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n[Ll]ogs/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUnit\n*.VisualState.xml\nTestResult.xml\nnunit-*.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# ASP.NET Scaffolding\nScaffoldingReadMe.txt\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.tlog\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Coverlet is a free, cross platform Code Coverage Tool\ncoverage*.json\ncoverage*.xml\ncoverage*.info\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# NuGet Symbol Packages\n*.snupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n*.appxbundle\n*.appxupload\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!?*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- [Bb]ackup.rdl\n*- [Bb]ackup ([0-9]).rdl\n*- [Bb]ackup ([0-9][0-9]).rdl\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio 6 auto-generated project file (contains which files were open etc.)\n*.vbp\n\n# Visual Studio 6 workspace and project file (working project files containing files to include in project)\n*.dsw\n*.dsp\n\n# Visual Studio 6 technical files\n*.ncb\n*.aps\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# CodeRush personal settings\n.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n.mfractor/\n\n# Local History for Visual Studio\n.localhistory/\n\n# Visual Studio History (VSHistory) files\n.vshistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb\n\n# Backup folder for Package Reference Convert tool in Visual Studio 2017\nMigrationBackup/\n\n# Ionide (cross platform F# VS Code tools) working folder\n.ionide/\n\n# Fody - auto-generated XML schema\nFodyWeavers.xsd\n\n# VS Code files for those working on multiple tools\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n*.code-workspace\n\n# Local History for Visual Studio Code\n.history/\n\n# Windows Installer files from build outputs\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n\n# JetBrains Rider\n*.sln.iml\n"
  },
  {
    "path": "BuildAllTargets.cmd",
    "content": "@setlocal\n@echo off\n\nrem Change to the current folder.\ncd \"%~dp0\"\n\nrem Remove the output folder for a fresh compile.\nrd /s /q Output\n\nrem Initialize Visual Studio environment\nset VisualStudioInstallerFolder=\"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\"\nif %PROCESSOR_ARCHITECTURE%==x86 set VisualStudioInstallerFolder=\"%ProgramFiles%\\Microsoft Visual Studio\\Installer\"\npushd %VisualStudioInstallerFolder%\nfor /f \"usebackq tokens=*\" %%i in (`vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do (\n  set VisualStudioInstallDir=%%i\n)\npopd\ncall \"%VisualStudioInstallDir%\\VC\\Auxiliary\\Build\\vcvarsall.bat\" x86\n\nrem Build all targets\nMSBuild -binaryLogger:Output\\BuildAllTargets.binlog -m BuildAllTargets.proj\n\n@endlocal"
  },
  {
    "path": "BuildAllTargets.proj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project \n  DefaultTargets=\"Restore;Build\"\n  xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <SolutionPath>$(MSBuildThisFileDirectory)NanaRun.slnx</SolutionPath>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"$(SolutionPath)\">\n      <AdditionalProperties>Configuration=Debug;Platform=x86</AdditionalProperties>   \n    </ProjectReference>\n    <ProjectReference Include=\"$(SolutionPath)\">\n      <AdditionalProperties>Configuration=Release;Platform=x86</AdditionalProperties>   \n    </ProjectReference>\n    <ProjectReference Include=\"$(SolutionPath)\">\n      <AdditionalProperties>Configuration=Debug;Platform=x64</AdditionalProperties>   \n    </ProjectReference>\n    <ProjectReference Include=\"$(SolutionPath)\">\n      <AdditionalProperties>Configuration=Release;Platform=x64</AdditionalProperties>   \n    </ProjectReference>\n    <ProjectReference Include=\"$(SolutionPath)\">\n      <AdditionalProperties>Configuration=Debug;Platform=ARM64</AdditionalProperties>   \n    </ProjectReference>\n    <ProjectReference Include=\"$(SolutionPath)\">\n      <AdditionalProperties>Configuration=Release;Platform=ARM64</AdditionalProperties>   \n    </ProjectReference>\n  </ItemGroup>\n  <Target Name=\"Restore\">\n    <MSBuild\n      Projects=\"@(ProjectReference)\"\n      Targets=\"Restore\"\n      StopOnFirstFailure=\"True\"\n      Properties=\"PreferredToolArchitecture=x64\" />\n  </Target>\n  <Target Name=\"Build\">\n    <MSBuild\n      Projects=\"@(ProjectReference)\"\n      Targets=\"Build\"\n      BuildInParallel=\"True\"\n      StopOnFirstFailure=\"True\"\n      Properties=\"PreferredToolArchitecture=x64\" />\n  </Target>\n</Project>"
  },
  {
    "path": "BuildInstallers.cmd",
    "content": "@setlocal\n@echo off\n\nrem Change to the current folder.\ncd \"%~dp0\"\n\nrem Remove the SynthRdp installation image output folder for a fresh compile.\nrd /s /q Output\\SynthRdpInstallationImage\n\nrem Generate SynthRdp installer\nTools\\ISCC.exe SynthRdp\\SynthRdp.iss\n\nrem Copy SynthRdp AutoRun.inf\ncopy SynthRdp\\AutoRun.inf Output\\SynthRdpInstallationImage\n\nrem Generate SynthRdp installation image\nTools\\oscdimg.exe -u1 -udfver102 -lSynthRdp Output\\SynthRdpInstallationImage Output\\SynthRdp.iso\n\n@endlocal"
  },
  {
    "path": "Directory.Build.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <MileProjectOutputPath>$(MSBuildThisFileDirectory)Output\\</MileProjectOutputPath>\n  </PropertyGroup>\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Build.props\" />\n</Project>"
  },
  {
    "path": "Documents/People.md",
    "content": "﻿# Relevant People\n\n## Notice\n\n- This list sort in alphabetical order.\n\n## Development Team\n\n- Kenji Mouri ([https://github.com/MouriNaruto](https://github.com/MouriNaruto))\n\n## Logo Designers\n\n- Shomnipotence ([https://github.com/Shomnipotence](https://github.com/Shomnipotence))\n\n## Special thanks\n\n- mingkuang ([https://github.com/mingkuang-Chuyu](https://github.com/mingkuang-Chuyu))\n"
  },
  {
    "path": "Documents/ReleaseNotes.md",
    "content": "﻿# NanaRun Release Notes\n\nFor preview versions, please read \n[NanaRun Preview Release Notes](ReleaseNotesPreview.md).\n"
  },
  {
    "path": "Documents/ReleaseNotesPreview.md",
    "content": "﻿# NanaRun Preview Release Notes\n\nFor stable versions, please read [NanaRun Release Notes](ReleaseNotes.md).\n\n**NanaRun 1.0 Preview 3 (1.0.92.0)**\n\n- Introduce the SynthRdp tool.\n- Add short form command line options support for MinSudo. (Suggested by\n  he3als.)\n- Update icon assets. (Designed by Shomnipotence.)\n- Adjust several implementations.\n\n**NanaRun 1.0 Preview 2 (1.0.18.0)**\n\n- Remove standard handle settings because child process will inherit the \n  parent's console for MinSudo.\n- Update application icon. (Designed by Shomnipotence.)\n- Make sure ignores CTRL+C signals for MinSudo itself to solve unexcepted\n  behaviors.\n- Fix current directory issue when put MinSudo into System32 folder. (Thanks to\n  Slemoon.)\n- Add System and TrustedInstaller mode for MinSudo.\n- Add enable all privileges mode support for MinSudo.\n\n**NanaRun 1.0 Preview 1 (1.0.5.0)**\n\n- Implement MinSudo.\n"
  },
  {
    "path": "Documents/Versioning.md",
    "content": "﻿# NanaRun Versioning\n\nThis document applies to all versions of NanaRun.\n\n## Version Format\n\n- Simple Version: `<Major>.<Minor> <Tag>`\n  - Example: `9.0 Preview 1`\n- Binary Version: `<Major>.<Minor>.<Build>.<Revision>`\n  - Example: `9.0.2654.0`\n\n## The rule for build and revision number\n\nThe build number is the number of days since May 1, 2024 because that day is the\n10th anniversary of the first version of NSudo is created and published.\n\n~~The build number is the number of days since May 16, 2022 because the first\nversion of NanaRun is created and published on that day.~~\n\nThe revision number is the number of releases releases in the day corresponding\nto the build number, and it counts from zero. So the first revision is 0 and \nthe second revision is 1.\n"
  },
  {
    "path": "License.md",
    "content": "﻿# NanaRun License\n\nFor giving the maximum respect for the upstream projects and following the \nphilosophy about open-source software from Kenji Mouri (MouriNaruto), the one\nof the M2-Team founders. \n\nThe source code of NanaRun (not including the source code from third-party \nlibraries) is distributed under the MIT License.\n\nThe application file association icons of NanaRun (these contents are only in \nthe `Assets` folder) are designed by Shomnipotence and authorized to the \nNanaRun project, and it is distributed under the CC BY-ND 4.0 License.\n\nThe source code from the third-party libraries is distributed under the original\nlicense used in the third-party libraries.\n\nThis permission notice shall be included in all copies or substantial portions\nof the Software.\n\n### The philosophy about open-source software from Kenji Mouri (MouriNaruto)\n\n- The source code from the third-party projects should be distributed under \n  their original licenses to give the maximum respect for the upstream \n  projects.\n\n- Don't make your software open source if you don't want your source code or\n  ideas used in proprietary software. Because they always have the way to cross\n  restrictions if they really want to do, even you distributed your source code\n  under the strictest copyleft license, they can use clean room to resolve it.\n\n- I prefer permissive licenses because using copyleft licenses will make you\n  feel anxious in most cases because you always need to worry about someone\n  using your source code in proprietary software. So, I choose to give the\n  maximum respect to users, and I also hope people can try their best to treat\n  others kindly.\n\n### The MIT License\n\n```\nThe MIT License (MIT)\n\nCopyright (c) M2-Team and Contributors. All rights reserved.\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.\n```\n\n### The CC BY-ND 4.0 License\n\n```\nCopyright (c) Shomnipotence and M2-Team. All rights reserved.\n\nThis work is licensed under a Creative Commons Attribution-NoDerivatives 4.0\nInternational License.\n\nAttribution-NoDerivatives 4.0 International\n\n=======================================================================\n\nCreative Commons Corporation (\"Creative Commons\") is not a law firm and\ndoes not provide legal services or legal advice. Distribution of\nCreative Commons public licenses does not create a lawyer-client or\nother relationship. Creative Commons makes its licenses and related\ninformation available on an \"as-is\" basis. Creative Commons gives no\nwarranties regarding its licenses, any material licensed under their\nterms and conditions, or any related information. Creative Commons\ndisclaims all liability for damages resulting from their use to the\nfullest extent possible.\n\nUsing Creative Commons Public Licenses\n\nCreative Commons public licenses provide a standard set of terms and\nconditions that creators and other rights holders may use to share\noriginal works of authorship and other material subject to copyright\nand certain other rights specified in the public license below. The\nfollowing considerations are for informational purposes only, are not\nexhaustive, and do not form part of our licenses.\n\n     Considerations for licensors: Our public licenses are\n     intended for use by those authorized to give the public\n     permission to use material in ways otherwise restricted by\n     copyright and certain other rights. Our licenses are\n     irrevocable. Licensors should read and understand the terms\n     and conditions of the license they choose before applying it.\n     Licensors should also secure all rights necessary before\n     applying our licenses so that the public can reuse the\n     material as expected. Licensors should clearly mark any\n     material not subject to the license. This includes other CC-\n     licensed material, or material used under an exception or\n     limitation to copyright. More considerations for licensors:\n    wiki.creativecommons.org/Considerations_for_licensors\n\n     Considerations for the public: By using one of our public\n     licenses, a licensor grants the public permission to use the\n     licensed material under specified terms and conditions. If\n     the licensor's permission is not necessary for any reason--for\n     example, because of any applicable exception or limitation to\n     copyright--then that use is not regulated by the license. Our\n     licenses grant only permissions under copyright and certain\n     other rights that a licensor has authority to grant. Use of\n     the licensed material may still be restricted for other\n     reasons, including because others have copyright or other\n     rights in the material. A licensor may make special requests,\n     such as asking that all changes be marked or described.\n     Although not required by our licenses, you are encouraged to\n     respect those requests where reasonable. More considerations\n     for the public:\n    wiki.creativecommons.org/Considerations_for_licensees\n\n\n=======================================================================\n\nCreative Commons Attribution-NoDerivatives 4.0 International Public\nLicense\n\nBy exercising the Licensed Rights (defined below), You accept and agree\nto be bound by the terms and conditions of this Creative Commons\nAttribution-NoDerivatives 4.0 International Public License (\"Public\nLicense\"). To the extent this Public License may be interpreted as a\ncontract, You are granted the Licensed Rights in consideration of Your\nacceptance of these terms and conditions, and the Licensor grants You\nsuch rights in consideration of benefits the Licensor receives from\nmaking the Licensed Material available under these terms and\nconditions.\n\n\nSection 1 -- Definitions.\n\n  a. Adapted Material means material subject to Copyright and Similar\n     Rights that is derived from or based upon the Licensed Material\n     and in which the Licensed Material is translated, altered,\n     arranged, transformed, or otherwise modified in a manner requiring\n     permission under the Copyright and Similar Rights held by the\n     Licensor. For purposes of this Public License, where the Licensed\n     Material is a musical work, performance, or sound recording,\n     Adapted Material is always produced where the Licensed Material is\n     synched in timed relation with a moving image.\n\n  b. Copyright and Similar Rights means copyright and/or similar rights\n     closely related to copyright including, without limitation,\n     performance, broadcast, sound recording, and Sui Generis Database\n     Rights, without regard to how the rights are labeled or\n     categorized. For purposes of this Public License, the rights\n     specified in Section 2(b)(1)-(2) are not Copyright and Similar\n     Rights.\n\n  c. Effective Technological Measures means those measures that, in the\n     absence of proper authority, may not be circumvented under laws\n     fulfilling obligations under Article 11 of the WIPO Copyright\n     Treaty adopted on December 20, 1996, and/or similar international\n     agreements.\n\n  d. Exceptions and Limitations means fair use, fair dealing, and/or\n     any other exception or limitation to Copyright and Similar Rights\n     that applies to Your use of the Licensed Material.\n\n  e. Licensed Material means the artistic or literary work, database,\n     or other material to which the Licensor applied this Public\n     License.\n\n  f. Licensed Rights means the rights granted to You subject to the\n     terms and conditions of this Public License, which are limited to\n     all Copyright and Similar Rights that apply to Your use of the\n     Licensed Material and that the Licensor has authority to license.\n\n  g. Licensor means the individual(s) or entity(ies) granting rights\n     under this Public License.\n\n  h. Share means to provide material to the public by any means or\n     process that requires permission under the Licensed Rights, such\n     as reproduction, public display, public performance, distribution,\n     dissemination, communication, or importation, and to make material\n     available to the public including in ways that members of the\n     public may access the material from a place and at a time\n     individually chosen by them.\n\n  i. Sui Generis Database Rights means rights other than copyright\n     resulting from Directive 96/9/EC of the European Parliament and of\n     the Council of 11 March 1996 on the legal protection of databases,\n     as amended and/or succeeded, as well as other essentially\n     equivalent rights anywhere in the world.\n\n  j. You means the individual or entity exercising the Licensed Rights\n     under this Public License. Your has a corresponding meaning.\n\n\nSection 2 -- Scope.\n\n  a. License grant.\n\n       1. Subject to the terms and conditions of this Public License,\n          the Licensor hereby grants You a worldwide, royalty-free,\n          non-sublicensable, non-exclusive, irrevocable license to\n          exercise the Licensed Rights in the Licensed Material to:\n\n            a. reproduce and Share the Licensed Material, in whole or\n               in part; and\n\n            b. produce and reproduce, but not Share, Adapted Material.\n\n       2. Exceptions and Limitations. For the avoidance of doubt, where\n          Exceptions and Limitations apply to Your use, this Public\n          License does not apply, and You do not need to comply with\n          its terms and conditions.\n\n       3. Term. The term of this Public License is specified in Section\n          6(a).\n\n       4. Media and formats; technical modifications allowed. The\n          Licensor authorizes You to exercise the Licensed Rights in\n          all media and formats whether now known or hereafter created,\n          and to make technical modifications necessary to do so. The\n          Licensor waives and/or agrees not to assert any right or\n          authority to forbid You from making technical modifications\n          necessary to exercise the Licensed Rights, including\n          technical modifications necessary to circumvent Effective\n          Technological Measures. For purposes of this Public License,\n          simply making modifications authorized by this Section 2(a)\n          (4) never produces Adapted Material.\n\n       5. Downstream recipients.\n\n            a. Offer from the Licensor -- Licensed Material. Every\n               recipient of the Licensed Material automatically\n               receives an offer from the Licensor to exercise the\n               Licensed Rights under the terms and conditions of this\n               Public License.\n\n            b. No downstream restrictions. You may not offer or impose\n               any additional or different terms or conditions on, or\n               apply any Effective Technological Measures to, the\n               Licensed Material if doing so restricts exercise of the\n               Licensed Rights by any recipient of the Licensed\n               Material.\n\n       6. No endorsement. Nothing in this Public License constitutes or\n          may be construed as permission to assert or imply that You\n          are, or that Your use of the Licensed Material is, connected\n          with, or sponsored, endorsed, or granted official status by,\n          the Licensor or others designated to receive attribution as\n          provided in Section 3(a)(1)(A)(i).\n\n  b. Other rights.\n\n       1. Moral rights, such as the right of integrity, are not\n          licensed under this Public License, nor are publicity,\n          privacy, and/or other similar personality rights; however, to\n          the extent possible, the Licensor waives and/or agrees not to\n          assert any such rights held by the Licensor to the limited\n          extent necessary to allow You to exercise the Licensed\n          Rights, but not otherwise.\n\n       2. Patent and trademark rights are not licensed under this\n          Public License.\n\n       3. To the extent possible, the Licensor waives any right to\n          collect royalties from You for the exercise of the Licensed\n          Rights, whether directly or through a collecting society\n          under any voluntary or waivable statutory or compulsory\n          licensing scheme. In all other cases the Licensor expressly\n          reserves any right to collect such royalties.\n\n\nSection 3 -- License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the\nfollowing conditions.\n\n  a. Attribution.\n\n       1. If You Share the Licensed Material, You must:\n\n            a. retain the following if it is supplied by the Licensor\n               with the Licensed Material:\n\n                 i. identification of the creator(s) of the Licensed\n                    Material and any others designated to receive\n                    attribution, in any reasonable manner requested by\n                    the Licensor (including by pseudonym if\n                    designated);\n\n                ii. a copyright notice;\n\n               iii. a notice that refers to this Public License;\n\n                iv. a notice that refers to the disclaimer of\n                    warranties;\n\n                 v. a URI or hyperlink to the Licensed Material to the\n                    extent reasonably practicable;\n\n            b. indicate if You modified the Licensed Material and\n               retain an indication of any previous modifications; and\n\n            c. indicate the Licensed Material is licensed under this\n               Public License, and include the text of, or the URI or\n               hyperlink to, this Public License.\n\n          For the avoidance of doubt, You do not have permission under\n          this Public License to Share Adapted Material.\n\n       2. You may satisfy the conditions in Section 3(a)(1) in any\n          reasonable manner based on the medium, means, and context in\n          which You Share the Licensed Material. For example, it may be\n          reasonable to satisfy the conditions by providing a URI or\n          hyperlink to a resource that includes the required\n          information.\n\n       3. If requested by the Licensor, You must remove any of the\n          information required by Section 3(a)(1)(A) to the extent\n          reasonably practicable.\n\n\nSection 4 -- Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that\napply to Your use of the Licensed Material:\n\n  a. for the avoidance of doubt, Section 2(a)(1) grants You the right\n     to extract, reuse, reproduce, and Share all or a substantial\n     portion of the contents of the database, provided You do not Share\n     Adapted Material;\n  b. if You include all or a substantial portion of the database\n     contents in a database in which You have Sui Generis Database\n     Rights, then the database in which You have Sui Generis Database\n     Rights (but not its individual contents) is Adapted Material; and\n  c. You must comply with the conditions in Section 3(a) if You Share\n     all or a substantial portion of the contents of the database.\n\nFor the avoidance of doubt, this Section 4 supplements and does not\nreplace Your obligations under this Public License where the Licensed\nRights include other Copyright and Similar Rights.\n\n\nSection 5 -- Disclaimer of Warranties and Limitation of Liability.\n\n  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE\n     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS\n     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF\n     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,\n     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,\n     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR\n     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,\n     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT\n     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT\n     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.\n\n  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE\n     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,\n     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,\n     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,\n     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR\n     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN\n     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR\n     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR\n     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.\n\n  c. The disclaimer of warranties and limitation of liability provided\n     above shall be interpreted in a manner that, to the extent\n     possible, most closely approximates an absolute disclaimer and\n     waiver of all liability.\n\n\nSection 6 -- Term and Termination.\n\n  a. This Public License applies for the term of the Copyright and\n     Similar Rights licensed here. However, if You fail to comply with\n     this Public License, then Your rights under this Public License\n     terminate automatically.\n\n  b. Where Your right to use the Licensed Material has terminated under\n     Section 6(a), it reinstates:\n\n       1. automatically as of the date the violation is cured, provided\n          it is cured within 30 days of Your discovery of the\n          violation; or\n\n       2. upon express reinstatement by the Licensor.\n\n     For the avoidance of doubt, this Section 6(b) does not affect any\n     right the Licensor may have to seek remedies for Your violations\n     of this Public License.\n\n  c. For the avoidance of doubt, the Licensor may also offer the\n     Licensed Material under separate terms or conditions or stop\n     distributing the Licensed Material at any time; however, doing so\n     will not terminate this Public License.\n\n  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public\n     License.\n\n\nSection 7 -- Other Terms and Conditions.\n\n  a. The Licensor shall not be bound by any additional or different\n     terms or conditions communicated by You unless expressly agreed.\n\n  b. Any arrangements, understandings, or agreements regarding the\n     Licensed Material not stated herein are separate from and\n     independent of the terms and conditions of this Public License.\n\n\nSection 8 -- Interpretation.\n\n  a. For the avoidance of doubt, this Public License does not, and\n     shall not be interpreted to, reduce, limit, restrict, or impose\n     conditions on any use of the Licensed Material that could lawfully\n     be made without permission under this Public License.\n\n  b. To the extent possible, if any provision of this Public License is\n     deemed unenforceable, it shall be automatically reformed to the\n     minimum extent necessary to make it enforceable. If the provision\n     cannot be reformed, it shall be severed from this Public License\n     without affecting the enforceability of the remaining terms and\n     conditions.\n\n  c. No term or condition of this Public License will be waived and no\n     failure to comply consented to unless expressly agreed to by the\n     Licensor.\n\n  d. Nothing in this Public License constitutes or may be interpreted\n     as a limitation upon, or waiver of, any privileges and immunities\n     that apply to the Licensor or You, including from the legal\n     processes of any jurisdiction or authority.\n\n=======================================================================\n\nCreative Commons is not a party to its public\nlicenses. Notwithstanding, Creative Commons may elect to apply one of\nits public licenses to material it publishes and in those instances\nwill be considered the “Licensor.” The text of the Creative Commons\npublic licenses is dedicated to the public domain under the CC0 Public\nDomain Dedication. Except for the limited purpose of indicating that\nmaterial is shared under a Creative Commons public license or as\notherwise permitted by the Creative Commons policies published at\ncreativecommons.org/policies, Creative Commons does not authorize the\nuse of the trademark \"Creative Commons\" or any other trademark or logo\nof Creative Commons without its prior written consent including,\nwithout limitation, in connection with any unauthorized modifications\nto any of its public licenses or any other arrangements,\nunderstandings, or agreements concerning use of licensed material. For\nthe avoidance of doubt, this paragraph does not form part of the\npublic licenses.\n\nCreative Commons may be contacted at creativecommons.org.\n```\n\n### The third-party libraries used in NanaRun\n\n- C++/WinRT, https://github.com/microsoft/cppwinrt\n- Mile.Detours, https://github.com/ProjectMile/Mile.Detours\n- Mile.Project.Windows, https://github.com/ProjectMile/Mile.Project.Windows\n- VC-LTL, https://github.com/Chuyu-Team/VC-LTL5\n"
  },
  {
    "path": "MinSudo/MinSudo.cpp",
    "content": "﻿/*\n * PROJECT:    NanaRun\n * FILE:       MinSudo.cpp\n * PURPOSE:    Implementation for MinSudo\n *\n * LICENSE:    The MIT License\n *\n * MAINTAINER: MouriNaruto (Kenji.Mouri@outlook.com)\n */\n\n#include <Windows.h>\n\n#include <WtsApi32.h>\n#pragma comment(lib, \"WtsApi32.lib\")\n\n#include <Userenv.h>\n#pragma comment(lib, \"Userenv.lib\")\n\n#include <cstdint>\n#include <cwchar>\n\n#include <map>\n#include <string>\n#include <vector>\n\n#include <Mile.Project.Version.h>\n\n#include \"resource.h\"\n\n#include <Mile.Helpers.CppBase.h>\n\nnamespace\n{\n    void SplitCommandLineEx(\n        std::wstring const& CommandLine,\n        std::vector<std::wstring> const& OptionPrefixes,\n        std::vector<std::wstring> const& OptionParameterSeparators,\n        std::wstring& ApplicationName,\n        std::map<std::wstring, std::wstring>& OptionsAndParameters,\n        std::wstring& UnresolvedCommandLine)\n    {\n        ApplicationName.clear();\n        OptionsAndParameters.clear();\n        UnresolvedCommandLine.clear();\n\n        size_t arg_size = 0;\n        for (auto& SplitArgument : Mile::SplitCommandLineWideString(CommandLine))\n        {\n            // We need to process the application name at the beginning.\n            if (ApplicationName.empty())\n            {\n                // For getting the unresolved command line, we need to cumulate\n                // length which including spaces.\n                arg_size += SplitArgument.size() + 1;\n\n                // Save\n                ApplicationName = SplitArgument;\n            }\n            else\n            {\n                bool IsOption = false;\n                size_t OptionPrefixLength = 0;\n\n                for (auto& OptionPrefix : OptionPrefixes)\n                {\n                    if (0 == _wcsnicmp(\n                        SplitArgument.c_str(),\n                        OptionPrefix.c_str(),\n                        OptionPrefix.size()))\n                    {\n                        IsOption = true;\n                        OptionPrefixLength = OptionPrefix.size();\n                    }\n                }\n\n                if (IsOption)\n                {\n                    // For getting the unresolved command line, we need to cumulate\n                    // length which including spaces.\n                    arg_size += SplitArgument.size() + 1;\n\n                    // Get the option name and parameter.\n\n                    wchar_t* OptionStart = &SplitArgument[0] + OptionPrefixLength;\n                    wchar_t* ParameterStart = nullptr;\n\n                    for (auto& OptionParameterSeparator\n                        : OptionParameterSeparators)\n                    {\n                        wchar_t* Result = wcsstr(\n                            OptionStart,\n                            OptionParameterSeparator.c_str());\n                        if (nullptr == Result)\n                        {\n                            continue;\n                        }\n\n                        Result[0] = L'\\0';\n                        ParameterStart = Result + OptionParameterSeparator.size();\n\n                        break;\n                    }\n\n                    // Save\n                    OptionsAndParameters[(OptionStart ? OptionStart : L\"\")] =\n                        (ParameterStart ? ParameterStart : L\"\");\n                }\n                else\n                {\n                    // Get the approximate location of the unresolved command line.\n                    // We use \"(arg_size - 1)\" to ensure that the program path\n                    // without quotes can also correctly parse.\n                    wchar_t* search_start =\n                        const_cast<wchar_t*>(CommandLine.c_str()) + (arg_size - 1);\n\n                    // Get the unresolved command line. Search for the beginning of\n                    // the first parameter delimiter called space and exclude the\n                    // first space by adding 1 to the result.\n                    wchar_t* command = wcsstr(search_start, L\" \") + 1;\n\n                    // Omit the space. (Thanks to wzzw.)\n                    while (command && *command == L' ')\n                    {\n                        ++command;\n                    }\n\n                    // Save\n                    if (command)\n                    {\n                        UnresolvedCommandLine = command;\n                    }\n\n                    break;\n                }\n            }\n        }\n    }\n\n    std::wstring GetCurrentProcessModulePath()\n    {\n        // 32767 is the maximum path length without the terminating null character.\n        std::wstring Path(32767, L'\\0');\n        Path.resize(::GetModuleFileNameW(\n            nullptr, &Path[0], static_cast<DWORD>(Path.size())));\n        return Path;\n    }\n\n    std::wstring GetWorkingDirectory()\n    {\n        // 32767 is the maximum path length without the terminating null character.\n        std::wstring Path(32767, L'\\0');\n        Path.resize(::GetCurrentDirectoryW(\n            static_cast<DWORD>(Path.size()), &Path[0]));\n        return Path;\n    }\n\n    void WriteToConsole(\n        std::wstring_view const& String)\n    {\n        HANDLE ConsoleOutputHandle = ::GetStdHandle(STD_OUTPUT_HANDLE);\n\n        DWORD NumberOfCharsWritten = 0;\n        if (!::WriteConsoleW(\n            ConsoleOutputHandle,\n            String.data(),\n            static_cast<DWORD>(String.size()),\n            &NumberOfCharsWritten,\n            nullptr))\n        {\n            std::string CurrentCodePageString = Mile::ToString(\n                ::GetConsoleOutputCP(),\n                String);\n\n            ::WriteFile(\n                ConsoleOutputHandle,\n                CurrentCodePageString.c_str(),\n                static_cast<DWORD>(CurrentCodePageString.size()),\n                &NumberOfCharsWritten,\n                nullptr);\n        }\n    }\n\n    std::map<std::string, std::wstring> ParseStringDictionary(\n        std::string_view const& Content)\n    {\n        constexpr std::string_view KeySeparator = \"\\r\\n- \";\n        constexpr std::string_view ValueStartSeparator = \"\\r\\n```\\r\\n\";\n        constexpr std::string_view ValueEndSeparator = \"\\r\\n```\";\n\n        std::map<std::string, std::wstring> Result;\n\n        if (Content.empty())\n        {\n            return Result;\n        }\n\n        const char* Start = Content.data();\n        const char* End = Start + Content.size();\n\n        while (Start < End)\n        {\n            const char* KeyStart = std::strstr(\n                Start,\n                KeySeparator.data());\n            if (!KeyStart)\n            {\n                break;\n            }\n            KeyStart += KeySeparator.size();\n\n            const char* KeyEnd = std::strstr(\n                KeyStart,\n                ValueStartSeparator.data());\n            if (!KeyEnd)\n            {\n                break;\n            }\n\n            const char* ValueStart =\n                KeyEnd + ValueStartSeparator.size();\n\n            const char* ValueEnd = std::strstr(\n                ValueStart,\n                ValueEndSeparator.data());\n            if (!ValueEnd)\n            {\n                break;\n            }\n\n            Start = ValueEnd + ValueEndSeparator.size();\n\n            Result.emplace(std::pair(\n                std::string(KeyStart, KeyEnd - KeyStart),\n                Mile::ToWideString(\n                    CP_UTF8,\n                    std::string(ValueStart, ValueEnd - ValueStart))));\n        }\n\n        return Result;\n    }\n\n    DWORD GetActiveSessionID()\n    {\n        DWORD Count = 0;\n        PWTS_SESSION_INFOW pSessionInfo = nullptr;\n        if (::WTSEnumerateSessionsW(\n            WTS_CURRENT_SERVER_HANDLE,\n            0,\n            1,\n            &pSessionInfo,\n            &Count))\n        {\n            for (DWORD i = 0; i < Count; ++i)\n            {\n                if (pSessionInfo[i].State == WTS_CONNECTSTATE_CLASS::WTSActive)\n                {\n                    return pSessionInfo[i].SessionId;\n                }\n            }\n\n            ::WTSFreeMemory(pSessionInfo);\n        }\n\n        // We should return session 0 for the case that no active session.\n        return 0;\n    }\n\n    BOOL CreateSystemToken(\n        _In_ DWORD DesiredAccess,\n        _Out_ PHANDLE TokenHandle)\n    {\n        // If the specified process is the System Idle Process (0x00000000), the\n        // function fails and the last error code is ERROR_INVALID_PARAMETER.\n        // So this is why 0 is the default value of dwLsassPID and dwWinLogonPID.\n\n        // For fix the issue that @_kod0k and @DennyAmaro mentioned in\n        // https://forums.mydigitallife.net/threads/59268/page-28#post-1672011 and\n        // https://forums.mydigitallife.net/threads/59268/page-28#post-1674985.\n        // Mile::CreateSystemToken will try to open the access token from lsass.exe\n        // for maximum privileges in the access token, and try to open the access\n        // token from winlogon.exe of current active session as fallback.\n\n        // If no source process of SYSTEM access token can be found, the error code\n        // will be HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER).\n\n        DWORD dwLsassPID = 0;\n        DWORD dwWinLogonPID = 0;\n        PWTS_PROCESS_INFOW pProcesses = nullptr;\n        DWORD dwProcessCount = 0;\n        DWORD dwSessionID = ::GetActiveSessionID();\n\n        if (::WTSEnumerateProcessesW(\n            WTS_CURRENT_SERVER_HANDLE,\n            0,\n            1,\n            &pProcesses,\n            &dwProcessCount))\n        {\n            for (DWORD i = 0; i < dwProcessCount; ++i)\n            {\n                PWTS_PROCESS_INFOW pProcess = &pProcesses[i];\n\n                if ((!pProcess->pProcessName) ||\n                    (!pProcess->pUserSid) ||\n                    (!::IsWellKnownSid(\n                        pProcess->pUserSid,\n                        WELL_KNOWN_SID_TYPE::WinLocalSystemSid)))\n                {\n                    continue;\n                }\n\n                if ((0 == dwLsassPID) &&\n                    (0 == pProcess->SessionId) &&\n                    (0 == ::_wcsicmp(L\"lsass.exe\", pProcess->pProcessName)))\n                {\n                    dwLsassPID = pProcess->ProcessId;\n                    continue;\n                }\n\n                if ((0 == dwWinLogonPID) &&\n                    (0 == dwSessionID || dwSessionID == pProcess->SessionId) &&\n                    (0 == ::_wcsicmp(L\"winlogon.exe\", pProcess->pProcessName)))\n                {\n                    dwWinLogonPID = pProcess->ProcessId;\n                    continue;\n                }\n            }\n\n            ::WTSFreeMemory(pProcesses);\n        }\n\n        BOOL Result = FALSE;\n        HANDLE SystemProcessHandle = nullptr;\n\n        SystemProcessHandle = ::OpenProcess(\n            PROCESS_QUERY_INFORMATION,\n            FALSE,\n            dwLsassPID);\n        if (!SystemProcessHandle)\n        {\n            SystemProcessHandle = ::OpenProcess(\n                PROCESS_QUERY_INFORMATION,\n                FALSE,\n                dwWinLogonPID);\n        }\n\n        if (SystemProcessHandle)\n        {\n            HANDLE SystemTokenHandle = nullptr;\n            if (::OpenProcessToken(\n                SystemProcessHandle,\n                TOKEN_DUPLICATE,\n                &SystemTokenHandle))\n            {\n                Result = ::DuplicateTokenEx(\n                    SystemTokenHandle,\n                    DesiredAccess,\n                    nullptr,\n                    SecurityIdentification,\n                    TokenPrimary,\n                    TokenHandle);\n\n                ::CloseHandle(SystemTokenHandle);\n            }\n\n            ::CloseHandle(SystemProcessHandle);\n        }\n\n        return Result;\n    }\n\n    BOOL OpenProcessTokenByProcessId(\n        _In_ DWORD ProcessId,\n        _In_ DWORD DesiredAccess,\n        _Out_ PHANDLE TokenHandle)\n    {\n        BOOL Result = FALSE;\n\n        HANDLE ProcessHandle = ::OpenProcess(\n            PROCESS_QUERY_INFORMATION,\n            FALSE,\n            ProcessId);\n        if (ProcessHandle)\n        {\n            Result = ::OpenProcessToken(\n                ProcessHandle,\n                DesiredAccess,\n                TokenHandle);\n\n            ::CloseHandle(ProcessHandle);\n        }\n\n        return Result;\n    }\n\n    BOOL OpenServiceProcessToken(\n        _In_ LPCWSTR ServiceName,\n        _In_ DWORD DesiredAccess,\n        _Out_ PHANDLE TokenHandle)\n    {\n        BOOL Result = FALSE;\n\n        SERVICE_STATUS_PROCESS ServiceStatus;\n        if (::MileStartService(\n            ServiceName,\n            &ServiceStatus))\n        {\n            Result = ::OpenProcessTokenByProcessId(\n                ServiceStatus.dwProcessId,\n                DesiredAccess,\n                TokenHandle);\n        }\n\n        return Result;\n    }\n\n    BOOL AdjustTokenPrivilegesSimple(\n        _In_ HANDLE TokenHandle,\n        _In_ PLUID_AND_ATTRIBUTES Privileges,\n        _In_ DWORD PrivilegeCount)\n    {\n        BOOL Result = FALSE;\n\n        if (Privileges && PrivilegeCount)\n        {\n            DWORD PrivilegesSize = sizeof(LUID_AND_ATTRIBUTES) * PrivilegeCount;\n            DWORD TokenPrivilegesSize = PrivilegesSize + sizeof(DWORD);\n\n            PTOKEN_PRIVILEGES TokenPrivileges =\n                reinterpret_cast<PTOKEN_PRIVILEGES>(\n                    ::MileAllocateMemory(TokenPrivilegesSize));\n            if (TokenPrivileges)\n            {\n                TokenPrivileges->PrivilegeCount = PrivilegeCount;\n                std::memcpy(\n                    TokenPrivileges->Privileges,\n                    Privileges,\n                    PrivilegesSize);\n\n                ::AdjustTokenPrivileges(\n                    TokenHandle,\n                    FALSE,\n                    TokenPrivileges,\n                    TokenPrivilegesSize,\n                    nullptr,\n                    nullptr);\n                Result = (ERROR_SUCCESS == ::GetLastError());\n\n                ::MileFreeMemory(TokenPrivileges);\n            }\n            else\n            {\n                ::SetLastError(ERROR_NOT_ENOUGH_MEMORY);\n            }\n        }\n        else\n        {\n            ::SetLastError(ERROR_INVALID_PARAMETER);\n        }\n\n        return Result;\n    }\n\n    BOOL GetTokenInformationWithMemory(\n        _In_ HANDLE TokenHandle,\n        _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,\n        _Out_ PVOID* OutputInformation)\n    {\n        if (!OutputInformation)\n        {\n            ::SetLastError(ERROR_INVALID_PARAMETER);\n            return FALSE;\n        }\n\n        *OutputInformation = nullptr;\n\n        BOOL Result = FALSE;\n\n        DWORD Length = 0;\n        ::GetTokenInformation(\n            TokenHandle,\n            TokenInformationClass,\n            nullptr,\n            0,\n            &Length);\n        if (ERROR_INSUFFICIENT_BUFFER == ::GetLastError())\n        {\n            *OutputInformation = ::MileAllocateMemory(Length);\n            if (*OutputInformation)\n            {\n                Result = ::GetTokenInformation(\n                    TokenHandle,\n                    TokenInformationClass,\n                    *OutputInformation,\n                    Length,\n                    &Length);\n                if (!Result)\n                {\n                    ::MileFreeMemory(*OutputInformation);\n                    *OutputInformation = nullptr;\n                }\n            }\n            else\n            {\n                ::SetLastError(ERROR_NOT_ENOUGH_MEMORY);\n            }\n        }\n\n        return Result;\n    }\n\n    BOOL AdjustTokenAllPrivileges(\n        _In_ HANDLE TokenHandle,\n        _In_ DWORD Attributes)\n    {\n        BOOL Result = FALSE;\n\n        PTOKEN_PRIVILEGES pTokenPrivileges = nullptr;\n        if (::GetTokenInformationWithMemory(\n            TokenHandle,\n            TokenPrivileges,\n            reinterpret_cast<PVOID*>(&pTokenPrivileges)))\n        {\n            for (DWORD i = 0; i < pTokenPrivileges->PrivilegeCount; ++i)\n            {\n                pTokenPrivileges->Privileges[i].Attributes = Attributes;\n            }\n\n            Result = ::AdjustTokenPrivilegesSimple(\n                TokenHandle,\n                pTokenPrivileges->Privileges,\n                pTokenPrivileges->PrivilegeCount);\n\n            ::MileFreeMemory(pTokenPrivileges);\n        }\n\n        return Result;\n    }\n\n    enum class TargetProcessTokenLevel : std::uint32_t\n    {\n        Standard = 0,\n        System = 1,\n        TrustedInstaller = 2,\n    };\n\n    BOOL SimpleCreateProcess(\n        _In_ TargetProcessTokenLevel TokenLevel,\n        _In_ bool Privileged,\n        _Inout_ LPWSTR lpCommandLine,\n        _In_opt_ LPCWSTR lpCurrentDirectory,\n        _In_ LPSTARTUPINFOW lpStartupInfo,\n        _Out_ LPPROCESS_INFORMATION lpProcessInformation)\n    {\n        BOOL Result = FALSE;\n        DWORD Error = ERROR_SUCCESS;\n\n        HANDLE CurrentProcessTokenHandle = INVALID_HANDLE_VALUE;\n        HANDLE ImpersonatedCurrentProcessTokenHandle = INVALID_HANDLE_VALUE;\n        LUID_AND_ATTRIBUTES RawPrivilege;\n        HANDLE SystemTokenHandle = INVALID_HANDLE_VALUE;\n        HANDLE ImpersonatedSystemTokenHandle = INVALID_HANDLE_VALUE;\n        HANDLE TrustedInstallerTokenHandle = INVALID_HANDLE_VALUE;\n        HANDLE TargetTokenHandle = INVALID_HANDLE_VALUE;\n        LPVOID EnvironmentBlock = nullptr;\n\n        auto Handler = Mile::ScopeExitTaskHandler([&]()\n        {\n            if (EnvironmentBlock)\n            {\n                ::DestroyEnvironmentBlock(EnvironmentBlock);\n            }\n\n            if (TargetTokenHandle != INVALID_HANDLE_VALUE)\n            {\n                ::CloseHandle(TargetTokenHandle);\n            }\n\n            if (TrustedInstallerTokenHandle != INVALID_HANDLE_VALUE)\n            {\n                ::CloseHandle(TrustedInstallerTokenHandle);\n            }\n\n            if (ImpersonatedSystemTokenHandle != INVALID_HANDLE_VALUE)\n            {\n                ::CloseHandle(ImpersonatedSystemTokenHandle);\n            }\n\n            if (SystemTokenHandle != INVALID_HANDLE_VALUE)\n            {\n                ::CloseHandle(SystemTokenHandle);\n            }\n\n            if (ImpersonatedCurrentProcessTokenHandle != INVALID_HANDLE_VALUE)\n            {\n                ::CloseHandle(ImpersonatedCurrentProcessTokenHandle);\n            }\n\n            if (CurrentProcessTokenHandle != INVALID_HANDLE_VALUE)\n            {\n                ::CloseHandle(CurrentProcessTokenHandle);\n            }\n\n            ::SetThreadToken(nullptr, nullptr);\n\n            if (!Result)\n            {\n                ::SetLastError(Error);\n            }\n        });\n\n        if (!::OpenProcessToken(\n            ::GetCurrentProcess(),\n            MAXIMUM_ALLOWED,\n            &CurrentProcessTokenHandle))\n        {\n            Error = ::GetLastError();\n            return Result;\n        }\n\n        if (!::DuplicateTokenEx(\n            CurrentProcessTokenHandle,\n            MAXIMUM_ALLOWED,\n            nullptr,\n            SecurityImpersonation,\n            TokenImpersonation,\n            &ImpersonatedCurrentProcessTokenHandle))\n        {\n            Error = ::GetLastError();\n            return Result;\n        }\n\n        if (!::LookupPrivilegeValueW(\n            nullptr,\n            SE_DEBUG_NAME,\n            &RawPrivilege.Luid))\n        {\n            Error = ::GetLastError();\n            return Result;\n        }\n\n        RawPrivilege.Attributes = SE_PRIVILEGE_ENABLED;\n\n        if (!::AdjustTokenPrivilegesSimple(\n            ImpersonatedCurrentProcessTokenHandle,\n            &RawPrivilege,\n            1))\n        {\n            Error = ::GetLastError();\n            return Result;\n        }\n\n        if (!::SetThreadToken(\n            nullptr,\n            ImpersonatedCurrentProcessTokenHandle))\n        {\n            Error = ::GetLastError();\n            return Result;\n        }\n\n        if (!::CreateSystemToken(\n            MAXIMUM_ALLOWED,\n            &SystemTokenHandle))\n        {\n            Error = ::GetLastError();\n            return Result;\n        }\n\n        if (!::DuplicateTokenEx(\n            SystemTokenHandle,\n            MAXIMUM_ALLOWED,\n            nullptr,\n            SecurityImpersonation,\n            TokenImpersonation,\n            &ImpersonatedSystemTokenHandle))\n        {\n            Error = ::GetLastError();\n            return Result;\n        }\n\n        if (!::AdjustTokenAllPrivileges(\n            ImpersonatedSystemTokenHandle,\n            SE_PRIVILEGE_ENABLED))\n        {\n            Error = ::GetLastError();\n            return Result;\n        }\n\n        if (!::SetThreadToken(\n            nullptr,\n            ImpersonatedSystemTokenHandle))\n        {\n            Error = ::GetLastError();\n            return Result;\n        }\n\n        if (TargetProcessTokenLevel::Standard == TokenLevel)\n        {\n            if (!::DuplicateTokenEx(\n                CurrentProcessTokenHandle,\n                MAXIMUM_ALLOWED,\n                nullptr,\n                SecurityIdentification,\n                TokenPrimary,\n                &TargetTokenHandle))\n            {\n                Error = ::GetLastError();\n                return Result;\n            }\n        }\n        else if (TargetProcessTokenLevel::System == TokenLevel)\n        {\n            if (!::DuplicateTokenEx(\n                SystemTokenHandle,\n                MAXIMUM_ALLOWED,\n                nullptr,\n                SecurityIdentification,\n                TokenPrimary,\n                &TargetTokenHandle))\n            {\n                Error = ::GetLastError();\n                return Result;\n            }\n        }\n        else if (TargetProcessTokenLevel::TrustedInstaller == TokenLevel)\n        {\n            if (!::OpenServiceProcessToken(\n                L\"TrustedInstaller\",\n                MAXIMUM_ALLOWED,\n                &TrustedInstallerTokenHandle))\n            {\n                Error = ::GetLastError();\n                return Result;\n            }\n\n            if (!::DuplicateTokenEx(\n                TrustedInstallerTokenHandle,\n                MAXIMUM_ALLOWED,\n                nullptr,\n                SecurityIdentification,\n                TokenPrimary,\n                &TargetTokenHandle))\n            {\n                Error = ::GetLastError();\n                return Result;\n            }\n        }\n        else\n        {\n            Error = ERROR_INVALID_PARAMETER;\n            return Result;\n        }\n\n        {\n            DWORD SessionID = ::GetActiveSessionID();\n            if (!::SetTokenInformation(\n                TargetTokenHandle,\n                TokenSessionId,\n                (PVOID)&SessionID,\n                sizeof(DWORD)))\n            {\n                Error = ::GetLastError();\n                return Result;\n            }\n        }\n\n        if (Privileged)\n        {\n            if (!::AdjustTokenAllPrivileges(\n                TargetTokenHandle,\n                SE_PRIVILEGE_ENABLED))\n            {\n                Error = ::GetLastError();\n                return Result;\n            }\n        }\n\n        if (!::CreateEnvironmentBlock(\n            &EnvironmentBlock,\n            CurrentProcessTokenHandle,\n            TRUE))\n        {\n            Error = ::GetLastError();\n            return Result;\n        }\n\n        Result = ::CreateProcessAsUserW(\n            TargetTokenHandle,\n            nullptr,\n            lpCommandLine,\n            nullptr,\n            nullptr,\n            TRUE,\n            CREATE_UNICODE_ENVIRONMENT,\n            EnvironmentBlock,\n            lpCurrentDirectory,\n            lpStartupInfo,\n            lpProcessInformation);\n\n        return Result;\n    }\n}\n\nint main()\n{\n    // Fall back to English in unsupported environment. (Temporary Hack)\n    // Reference: https://github.com/M2Team/NSudo/issues/56\n    switch (PRIMARYLANGID(::GetThreadUILanguage()))\n    {\n    case LANG_ENGLISH:\n    case LANG_CHINESE:\n        break;\n    default:\n        ::SetThreadUILanguage(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL));\n        break;\n    }\n\n    std::map<std::string, std::wstring> StringDictionary;\n\n    MILE_RESOURCE_INFO ResourceInfo = { 0 };\n    if (::MileLoadResource(\n        &ResourceInfo,\n        ::GetModuleHandleW(nullptr),\n        L\"Translations\",\n        MAKEINTRESOURCEW(IDR_TRANSLATIONS),\n        MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)))\n    {\n        StringDictionary = ::ParseStringDictionary(std::string_view(\n            reinterpret_cast<const char*>(ResourceInfo.Pointer),\n            ResourceInfo.Size));\n    }\n\n    std::wstring ApplicationName;\n    std::map<std::wstring, std::wstring> OptionsAndParameters;\n    std::wstring UnresolvedCommandLine;\n\n    ::SplitCommandLineEx(\n        std::wstring(::GetCommandLineW()),\n        std::vector<std::wstring>{ L\"-\", L\"/\", L\"--\" },\n        std::vector<std::wstring>{ L\"=\", L\":\" },\n        ApplicationName,\n        OptionsAndParameters,\n        UnresolvedCommandLine);\n\n    bool NoLogo = false;\n    bool Verbose = false;\n    std::wstring WorkDir;\n    TargetProcessTokenLevel TargetLevel = TargetProcessTokenLevel::Standard;\n    bool Privileged = false;\n\n    for (auto& Current : OptionsAndParameters)\n    {\n        if (0 == _wcsicmp(Current.first.c_str(), L\"NoLogo\") ||\n            0 == _wcsicmp(Current.first.c_str(), L\"NoL\"))\n        {\n            NoLogo = true;\n        }\n        else if (\n            0 == _wcsicmp(Current.first.c_str(), L\"Verbose\") ||\n            0 == _wcsicmp(Current.first.c_str(), L\"V\"))\n        {\n            Verbose = true;\n        }\n        else if (\n            0 == _wcsicmp(Current.first.c_str(), L\"WorkDir\") ||\n            0 == _wcsicmp(Current.first.c_str(), L\"WD\"))\n        {\n            WorkDir = Current.second;\n        }\n        else if (\n            0 == _wcsicmp(Current.first.c_str(), L\"System\") ||\n            0 == _wcsicmp(Current.first.c_str(), L\"S\"))\n        {\n            TargetLevel = TargetProcessTokenLevel::System;\n        }\n        else if (\n            0 == _wcsicmp(Current.first.c_str(), L\"TrustedInstaller\") ||\n            0 == _wcsicmp(Current.first.c_str(), L\"TI\"))\n        {\n            TargetLevel = TargetProcessTokenLevel::TrustedInstaller;\n        }\n        else if (\n            0 == _wcsicmp(Current.first.c_str(), L\"Privileged\") ||\n            0 == _wcsicmp(Current.first.c_str(), L\"P\"))\n        {\n            Privileged = true;\n        }\n    }\n\n    bool ShowHelp = false;\n    bool ShowInvalidCommandLine = false;\n\n    if (1 == OptionsAndParameters.size() && UnresolvedCommandLine.empty())\n    {\n        auto Current = *OptionsAndParameters.begin();\n\n        if (0 == _wcsicmp(Current.first.c_str(), L\"?\") ||\n            0 == _wcsicmp(Current.first.c_str(), L\"H\") ||\n            0 == _wcsicmp(Current.first.c_str(), L\"Help\"))\n        {\n            ShowHelp = true;\n        }\n        else if (\n            0 == _wcsicmp(Current.first.c_str(), L\"Version\") ||\n            0 == _wcsicmp(Current.first.c_str(), L\"Ver\"))\n        {\n            ::WriteToConsole(\n                L\"MinSudo \" MILE_PROJECT_VERSION_STRING L\" (Build \"\n                MILE_PROJECT_MACRO_TO_STRING(MILE_PROJECT_VERSION_BUILD) L\")\"\n                L\"\\r\\n\");\n            return 0;\n        }\n        else if (!(\n            NoLogo ||\n            Verbose ||\n            !WorkDir.empty() ||\n            TargetLevel != TargetProcessTokenLevel::Standard ||\n            Privileged))\n        {\n            ShowInvalidCommandLine = true;\n        }\n    }\n\n    if (!NoLogo)\n    {\n        ::WriteToConsole(\n            L\"MinSudo \" MILE_PROJECT_VERSION_STRING L\" (Build \"\n            MILE_PROJECT_MACRO_TO_STRING(MILE_PROJECT_VERSION_BUILD) L\")\" L\"\\r\\n\"\n            L\"(c) M2-Team and Contributors. All rights reserved.\\r\\n\"\n            L\"\\r\\n\");\n    }\n\n    if (ShowHelp)\n    {\n        ::WriteToConsole(StringDictionary[\"CommandLineHelp\"]);\n\n        return 0;\n    }\n    else if (ShowInvalidCommandLine)\n    {\n        ::WriteToConsole(StringDictionary[\"InvalidCommandLineError\"]);\n\n        return E_INVALIDARG;\n    }\n\n    ApplicationName = ::GetCurrentProcessModulePath();\n    if (UnresolvedCommandLine.empty())\n    {\n        UnresolvedCommandLine = L\"cmd.exe\";\n    }\n\n    if (Verbose)\n    {\n        std::wstring VerboseInformation;\n        VerboseInformation += StringDictionary[\"CommandLineNotice\"];\n        VerboseInformation += UnresolvedCommandLine;\n        VerboseInformation += L\"\\r\\n\";\n        ::WriteToConsole(VerboseInformation.c_str());\n    }\n\n    if (WorkDir.empty())\n    {\n        WorkDir = std::wstring(::GetWorkingDirectory());\n    }\n    if (L'\\\\' == WorkDir.back())\n    {\n        WorkDir.pop_back();\n    }\n\n    if (::MileIsCurrentProcessElevated())\n    {\n        ::FreeConsole();\n        ::AttachConsole(ATTACH_PARENT_PROCESS);\n\n        if (Verbose)\n        {\n            ::WriteToConsole(StringDictionary[\"Stage1Notice\"]);\n        }\n\n        STARTUPINFOW StartupInfo = { 0 };\n        PROCESS_INFORMATION ProcessInformation = { 0 };\n        StartupInfo.cb = sizeof(STARTUPINFOW);\n        if (::SimpleCreateProcess(\n            TargetLevel,\n            Privileged,\n            const_cast<LPWSTR>(UnresolvedCommandLine.c_str()),\n            WorkDir.c_str(),\n            &StartupInfo,\n            &ProcessInformation))\n        {\n            // Make sure ignores CTRL+C signals after creating the child\n            // process. Because that state is heritable, but we want to make\n            // child process support CTRL+C.\n            ::SetConsoleCtrlHandler(nullptr, TRUE);\n\n            ::CloseHandle(ProcessInformation.hThread);\n            ::WaitForSingleObjectEx(ProcessInformation.hProcess, INFINITE, FALSE);\n            ::CloseHandle(ProcessInformation.hProcess);\n        }\n        else\n        {\n            ::WriteToConsole(StringDictionary[\"Stage1Failed\"]);\n        }\n    }\n    else\n    {\n        if (Verbose)\n        {\n            ::WriteToConsole(StringDictionary[\"Stage0Notice\"]);\n        }\n\n        std::wstring TargetCommandLine = L\"--NoLogo \";\n        if (Verbose)\n        {\n            TargetCommandLine += L\"--Verbose \";\n        }\n        TargetCommandLine += L\"--WorkDir=\\\"\";\n        TargetCommandLine += WorkDir;\n        TargetCommandLine += L\"\\\" \";\n        if (TargetLevel == TargetProcessTokenLevel::System)\n        {\n            TargetCommandLine += L\"--System \";\n        }\n        else if (TargetLevel == TargetProcessTokenLevel::TrustedInstaller)\n        {\n            TargetCommandLine += L\"--TrustedInstaller \";\n        }\n        if (Privileged)\n        {\n            TargetCommandLine += L\"--Privileged \";\n        }\n        TargetCommandLine += UnresolvedCommandLine;\n\n        SHELLEXECUTEINFOW Information = { 0 };\n        Information.cbSize = sizeof(SHELLEXECUTEINFOW);\n        Information.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE;\n        Information.lpVerb = L\"runas\";\n        Information.lpFile = ApplicationName.c_str();\n        Information.lpParameters = TargetCommandLine.c_str();\n        if (::ShellExecuteExW(&Information))\n        {\n            // Make sure ignores CTRL+C signals after creating the child\n            // process. Because that state is heritable, but we want to make\n            // child process support CTRL+C.\n            ::SetConsoleCtrlHandler(nullptr, TRUE);\n\n            ::WaitForSingleObjectEx(Information.hProcess, INFINITE, FALSE);\n            ::CloseHandle(Information.hProcess);\n        }\n        else\n        {\n            ::WriteToConsole(StringDictionary[\"Stage0Failed\"]);\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "MinSudo/MinSudo.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n\t<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v2\">\n\t\t<security>\n\t\t\t<requestedPrivileges>\n\t\t\t\t<requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\"/>\n\t\t\t</requestedPrivileges>\n\t\t</security>\n\t</trustInfo>\n\t<compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n\t\t<application>\n\t\t\t<supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\"/>\n\t\t\t<supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>\n\t\t\t<supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n\t\t\t<supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>\n\t\t\t<supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>\n\t\t</application>\n\t</compatibility>\n</assembly>\n"
  },
  {
    "path": "MinSudo/MinSudo.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{99FA5072-6C05-4027-8C8B-EA3EC9BCF9E0}</ProjectGuid>\n    <RootNamespace>MinSudo</RootNamespace>\n    <MileProjectType>ConsoleApplication</MileProjectType>\n    <MileProjectManifestFile>MinSudo.manifest</MileProjectManifestFile>\n    <MileProjectEnableVCLTLSupport>true</MileProjectEnableVCLTLSupport>\n    <MileProjectUseProjectProperties>true</MileProjectUseProjectProperties>\n    <MileProjectCompanyName>M2-Team</MileProjectCompanyName>\n    <MileProjectFileDescription>MinSudo - Lightweight POSIX-style Sudo implementation for Windows</MileProjectFileDescription>\n    <MileProjectInternalName>MinSudo</MileProjectInternalName>\n    <MileProjectLegalCopyright>© M2-Team and Contributors. All rights reserved.</MileProjectLegalCopyright>\n    <MileProjectOriginalFilename>MinSudo.exe</MileProjectOriginalFilename>\n    <MileProjectProductName>NanaRun</MileProjectProductName>\n    <MileProjectVersion>1.0.$([System.DateTime]::Today.Subtract($([System.DateTime]::Parse('2024-05-01'))).TotalDays).0</MileProjectVersion>\n    <MileProjectVersionTag>Preview 3</MileProjectVersionTag>\n    <MileWindowsHelpersNoCppWinRTHelpers>true</MileWindowsHelpersNoCppWinRTHelpers>\n  </PropertyGroup>\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Platform.x86.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Platform.x64.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Platform.ARM64.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Cpp.Default.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Cpp.props\" />\n  <Import Project=\"..\\NanaRun.IconResource\\NanaRun.IconResource.props\" />\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <EnableEnhancedInstructionSet Condition=\"'$(Platform)'=='Win32'\">NoExtensions</EnableEnhancedInstructionSet>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"MinSudo.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Manifest Include=\"MinSudo.manifest\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"resource.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Resources\\en\\Translations.md\" />\n    <None Include=\"Resources\\zh-Hans\\Translations.md\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"MinSudo.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Mile.Windows.Helpers\">\n      <Version>1.0.1171</Version>\n    </PackageReference>\n  </ItemGroup>\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Cpp.targets\" />\n</Project>"
  },
  {
    "path": "MinSudo/MinSudo.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"MinSudo.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Manifest Include=\"MinSudo.manifest\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"resource.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"Resources\">\n      <UniqueIdentifier>{7b09b2fc-15c9-40d3-8c68-b33226a0b2cd}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Resources\\en\">\n      <UniqueIdentifier>{0e9f5c86-045b-493f-b15e-750b369fc678}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Resources\\zh-Hans\">\n      <UniqueIdentifier>{71ae93ee-4aa8-44b8-bc84-e680a9768fc5}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Resources\\en\\Translations.md\">\n      <Filter>Resources\\en</Filter>\n    </None>\n    <None Include=\"Resources\\zh-Hans\\Translations.md\">\n      <Filter>Resources\\zh-Hans</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"MinSudo.rc\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "MinSudo/Resources/en/Translations.md",
    "content": "﻿```\n* PROJECT:    NanaRun\n* FILE:       Translations.md\n* PURPOSE:    The English translation for MinSudo\n*\n* LICENSE:    The MIT License\n*\n* MAINTAINER: MouriNaruto (Kenji.Mouri@outlook.com)\n```\n\n- InvalidCommandLineError\n```\n[Error] Invalid command line parameters. (Use '/?', '-H' or '--Help' option for\nusage.)\n\n```\n- CommandLineNotice\n```\n[Info] Target Command Line: \n```\n- Stage0Notice\n```\n[Info] Enter the Stage 0 (non-elevated).\n\n```\n- Stage0Failed\n```\n[Error] ShellExecuteExW failed.\n\n```\n- Stage1Notice\n```\n[Info] Enter the Stage 1 (elevated).\n\n\n```\n- Stage1Failed\n```\n[Error] CreateProcessW failed.\n\n```\n- CommandLineHelp\n```\nFormat: MinSudo [Options] Command\n\nOptions:\n\n  --NoLogo, -NoL\n    Suppress copyright message.\n\n  --Verbose, -V\n    Show detailed information.\n\n  --WorkDir=[Path], -WD=[Path]\n    Set working directory.\n\n  --System, -S\n    Run as System instead of Administrator.\n\n  --TrustedInstaller, -TI\n    Run as TrustedInstaller instead of Administrator.\n\n  --Privileged, -P\n    Enable all privileges.\n\n  --Version, -Ver\n    Show version information.\n\n  /?, -H, --Help\n    Show this content.\n\nNotes:\n\n  - All command options are case-insensitive.\n  - MinSudo will execute \"cmd.exe\" if you don't specify another command.\n  - You can use the \"/\" or \"--\" override \"-\" and use the \"=\" override \":\" in \n    the command line parameters. For example, \"/Option:Value\" and \n    \"-Option=Value\" are equivalent.\n\nExample:\n\n  If you want to run \"whoami /all\" as elevated in the non-elevated Console, and\n  you don't want to show version information of MinSudo.\n  > MinSudo --NoLogo whoami /all\n\n```\n"
  },
  {
    "path": "MinSudo/Resources/zh-Hans/Translations.md",
    "content": "﻿```\n* PROJECT:    NanaRun\n* FILE:       Translations.md\n* PURPOSE:    The Chinese (Simplified) translation for MinSudo\n*\n* LICENSE:    The MIT License\n*\n* MAINTAINER: MouriNaruto (Kenji.Mouri@outlook.com)\n```\n\n- InvalidCommandLineError\n```\n[错误] 无效的命令行参数。 (使用 '/?', '-H' 或 '--Help' 选项获取用法。)\n\n```\n- CommandLineNotice\n```\n[信息] 目标命令行: \n```\n- Stage0Notice\n```\n[信息] 进入 0 阶段 (未提权).\n\n```\n- Stage0Failed\n```\n[信息] ShellExecuteExW 调用失败。\n\n```\n- Stage1Notice\n```\n[信息] 进入 1 阶段 (已提权).\n\n\n```\n- Stage1Failed\n```\n[错误] CreateProcessW 调用失败。\n\n```\n- CommandLineHelp\n```\n格式: MinSudo [选项] 命令\n\n选项:\n\n  --NoLogo, -NoL\n    隐藏版权信息。\n\n  --Verbose, -V\n    显示详细信息。\n\n  --WorkDir=[路径], -WD=[路径]\n    设置工作目录。\n\n  --System, -S\n    使用 System 而不是管理员执行。\n\n  --TrustedInstaller, -TI\n    使用 TrustedInstaller 而不是管理员执行。\n\n  --Privileged, -P\n    启用全部特权。\n\n  --Version, -Ver\n    显示版本信息。\n\n  /?, -H, --Help\n    显示该内容。\n\n提示:\n\n  - 所有命令选项不区分大小写。\n  - 如果你不指定其他命令，MinSudo 将执行 \"cmd.exe\"。\n  - 可以在命令行参数中使用 \"/\" 或 \"--\" 代替 \"-\" 和使用 \"=\" 代替 \":\"。例如\n    \"/Option:Value\" 和 \"-Option=Value\" 是等价的。\n\n用例:\n\n  如果你想在未提权的控制台下运行提权的 \"whoami /all\"，并且你不希望 MinSudo 显示\n  版本信息。\n  > MinSudo --NoLogo whoami /all\n\n```\n"
  },
  {
    "path": "MinSudo/resource.h",
    "content": "﻿//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ 生成的包含文件。\n// 供 MinSudo.rc 使用\n//\n#define IDR_TRANSLATIONS                101\n\n// Next default values for new objects\n//\n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        104\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1001\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "NanaRun/NanaRun.cpp",
    "content": "﻿/*\n * PROJECT:    NanaRun\n * FILE:       NanaRun.cpp\n * PURPOSE:    Implementation for NanaRun\n *\n * LICENSE:    The MIT License\n *\n * MAINTAINER: MouriNaruto (Kenji.Mouri@outlook.com)\n */\n\n#include <cstdint>\n#include <cwchar>\n#include <string>\n#include <vector>\n\nenum class AccessTokenSourceType : std::int32_t\n{\n    CurrentProcess = 0,\n    Process = 1,\n    System = 2,\n    CurrentSession = 3,\n    Session = 4,\n    Service = 5,\n    User = 6,\n};\n\nenum class MandatoryLabelType : std::int32_t\n{\n    Default = 0,\n    Untrusted = 1,\n    Low = 2,\n    Medium = 3,\n    MediumPlus = 4,\n    High = 5,\n    System = 6,\n    ProtectedProcess = 7,\n};\n\nenum class ProcessPriorityType : std::int32_t\n{\n    Default = 0,\n    Idle = 1,\n    BelowNormal = 2,\n    Normal = 3,\n    AboveNormal = 4,\n    High = 5,\n    RealTime = 6,\n};\n\nenum class ShowWindowModeType : std::int32_t\n{\n    Default = 0,\n    Show = 1,\n    Hide = 2,\n    Maximize = 3,\n    Minimize = 4\n};\n\nstruct EnvironmentConfiguration\n{\n    AccessTokenSourceType AccessTokenSource =\n        AccessTokenSourceType::CurrentProcess;\n    std::uint32_t Process = 0;\n    std::uint32_t Session = 0;\n    std::string ServiceName;\n    std::string UserName;\n    std::string UserPassword;\n\n    bool UseLinkedAccessToken = false;\n    bool UseLuaAccessToken = false;\n\n    bool EnableAllPrivileges = false;\n    bool RemoveAllPrivileges = false;\n    std::vector<std::string> ExcludedPrivileges;\n    std::vector<std::string> IncludedPrivileges;\n\n    MandatoryLabelType IntegrityLevel = MandatoryLabelType::Default;\n\n    bool InheritEnvironmentVariables = true;\n    std::vector<std::pair<std::string, std::string>> EnvironmentVariables;\n\n    ProcessPriorityType ProcessPriority = ProcessPriorityType::Default;\n\n    ShowWindowModeType ShowWindowMode = ShowWindowModeType::Default;\n\n    bool WaitForExit = false;\n\n    std::string CurrentDirectory;\n\n    bool UseCurrentConsole = false;\n};\n\nint main()\n{\n    std::wprintf(L\"Hello World! - NanaRun (Console)\");\n\n    return 0;\n}\n"
  },
  {
    "path": "NanaRun/NanaRun.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n\t<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v2\">\n\t\t<security>\n\t\t\t<requestedPrivileges>\n\t\t\t\t<requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\"/>\n\t\t\t</requestedPrivileges>\n\t\t</security>\n\t</trustInfo>\n\t<compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n\t\t<application>\n\t\t\t<supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\"/>\n\t\t\t<supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>\n\t\t\t<supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n\t\t\t<supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>\n\t\t\t<supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>\n\t\t</application>\n\t</compatibility>\n</assembly>\n"
  },
  {
    "path": "NanaRun/NanaRun.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{3D1A07C8-17B2-4E5F-AAC1-16BE522BD4D7}</ProjectGuid>\n    <RootNamespace>NanaRun</RootNamespace>\n    <MileProjectType>ConsoleApplication</MileProjectType>\n    <MileProjectManifestFile>NanaRun.manifest</MileProjectManifestFile>\n    <MileProjectEnableVCLTLSupport>true</MileProjectEnableVCLTLSupport>\n    <MileProjectUseProjectProperties>true</MileProjectUseProjectProperties>\n    <MileProjectCompanyName>M2-Team</MileProjectCompanyName>\n    <MileProjectFileDescription>NanaRun (Console)</MileProjectFileDescription>\n    <MileProjectInternalName>NanaRun</MileProjectInternalName>\n    <MileProjectLegalCopyright>© M2-Team and Contributors. All rights reserved.</MileProjectLegalCopyright>\n    <MileProjectOriginalFilename>NanaRun.exe</MileProjectOriginalFilename>\n    <MileProjectProductName>NanaRun</MileProjectProductName>\n    <MileProjectVersion>1.0.$([System.DateTime]::Today.Subtract($([System.DateTime]::Parse('2024-05-01'))).TotalDays).0</MileProjectVersion>\n    <MileProjectVersionTag>Preview 3</MileProjectVersionTag>\n    <MileWindowsHelpersNoCppWinRTHelpers>true</MileWindowsHelpersNoCppWinRTHelpers>\n  </PropertyGroup>\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Platform.x86.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Platform.x64.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Platform.ARM64.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Cpp.Default.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Cpp.props\" />\n  <Import Project=\"..\\NanaRun.IconResource\\NanaRun.IconResource.props\" />\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <EnableEnhancedInstructionSet Condition=\"'$(Platform)'=='Win32'\">NoExtensions</EnableEnhancedInstructionSet>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"NanaRun.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Manifest Include=\"NanaRun.manifest\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Mile.Windows.Helpers\">\n      <Version>1.0.1171</Version>\n    </PackageReference>\n    <PackageReference Include=\"Mile.Windows.Internal\">\n      <Version>1.0.3550</Version>\n    </PackageReference>\n  </ItemGroup>\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Cpp.targets\" />\n</Project>"
  },
  {
    "path": "NanaRun/NanaRun.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"NanaRun.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Manifest Include=\"NanaRun.manifest\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "NanaRun.IconResource/NanaRun.IconResource.h",
    "content": "﻿/*\n * PROJECT:    NanaRun\n * FILE:       NanaRun.IconResource.h\n * PURPOSE:    Windows icon resource for NanaRun\n *\n * LICENSE:    The MIT License\n *\n * MAINTAINER: MouriNaruto (Kenji.Mouri@outlook.com)\n */\n\n#define IDI_NANARUN                       101\n"
  },
  {
    "path": "NanaRun.IconResource/NanaRun.IconResource.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  PROJECT:    NanaRun\n  FILE:       NanaRun.IconResource.props\n  PURPOSE:    Windows icon resource for NanaRun\n\n  LICENSE:    The MIT License\n\n  MAINTAINER: MouriNaruto (Kenji.Mouri@outlook.com)\n-->\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <IncludePath>$(MSBuildThisFileDirectory);$(IncludePath)</IncludePath>\n  </PropertyGroup>\n  <Target Name=\"NanaRunBuildIconResource\" BeforeTargets=\"BeforeResourceCompile\">\n    <ItemGroup>\n      <ResourceCompile Include=\"$(MSBuildThisFileDirectory)NanaRun.IconResource.rc\" />\n    </ItemGroup>\n  </Target>\n</Project>"
  },
  {
    "path": "NanaRun.slnx",
    "content": "<Solution>\n  <Configurations>\n    <Platform Name=\"ARM64\" />\n    <Platform Name=\"x64\" />\n    <Platform Name=\"x86\" />\n  </Configurations>\n  <Project Path=\"MinSudo/MinSudo.vcxproj\" Id=\"99fa5072-6c05-4027-8c8b-ea3ec9bcf9e0\" />\n  <Project Path=\"NanaRun/NanaRun.vcxproj\" Id=\"3d1a07c8-17b2-4e5f-aac1-16be522bd4d7\" />\n  <Project Path=\"SynthRdp/SynthRdp.vcxproj\" Id=\"abfd05c2-4673-49ec-a23e-9ca53223eec2\" />\n  <Project Path=\"VirtualSmb/VirtualSmb.vcxproj\" Id=\"0a6fbd98-1210-4b36-a031-3e2d57e89de3\" />\n</Solution>\n"
  },
  {
    "path": "ReadMe.md",
    "content": "﻿# ![NanaRun](Assets/NanaRun.png) NanaRun\n\nApplication runtime environment customization utility\n\n## Development Status of Components\n\n- [x] MinSudo\n- [x] SynthRdp\n- [ ] NanaEAM\n- [ ] NanaKit\n- [ ] NanaRun (Console)\n- [ ] NanaRun (SDK)\n\n## System Requirements\n\n- MinSudo\n  - Supported OS: Windows Vista RTM (Build 6000.16386) or later\n  - Supported Platforms: x86 (32-bit and 64-bit) and ARM (64-bit)\n\n- SynthRdp\n  - Supported OS: Windows XP RTM (Build 2600) or later\n  - Supported Platforms: x86 (32-bit and 64-bit) and ARM (64-bit)\n\n## MinSudo\n\nMinSudo is a lightweight POSIX-style Sudo implementation for Windows.\n\nIt makes user possible to use elevated console apps in non-elevated consoles.\n\nFor safety, the implementation uses the UAC for elevation and don't support\ncredential cache. It also don't use homemade Windows service and any IPC \ninfrastructures.\n\nHere is the usage.\n\n```\nFormat: MinSudo [Options] Command\n\nOptions:\n\n  --NoLogo, -NoL\n    Suppress copyright message.\n\n  --Verbose, -V\n    Show detailed information.\n\n  --WorkDir=[Path], -WD=[Path]\n    Set working directory.\n\n  --System, -S\n    Run as System instead of Administrator.\n\n  --TrustedInstaller, -TI\n    Run as TrustedInstaller instead of Administrator.\n\n  --Privileged, -P\n    Enable all privileges.\n\n  --Version, -Ver\n    Show version information.\n\n  /?, -H, --Help\n    Show this content.\n\nNotes:\n\n  - All command options are case-insensitive.\n  - MinSudo will execute \"cmd.exe\" if you don't specify another command.\n  - You can use the \"/\" or \"--\" override \"-\" and use the \"=\" override \":\" in \n    the command line parameters. For example, \"/Option:Value\" and \n    \"-Option=Value\" are equivalent.\n\nExample:\n\n  If you want to run \"whoami /all\" as elevated in the non-elevated Console, and\n  you don't want to show version information of MinSudo.\n  > MinSudo --NoLogo whoami /all\n```\n\n## SynthRdp\n\nSynthRdp is a Hyper-V Enhanced Session Proxy Service for Windows, which can\nredirect RDP over VMBus pipe to any RDP over TCP socket, because the Hyper-V\nEnhanced Session is actually the RDP connection over the VMBus pipe.\n\n### Features\n\n- Make Hyper-V virtual machines with Windows 8 and earlier guest OSes support\n  Hyper-V Enhanced Session mode.\n- Act as a proxy service to make Hyper-V virtual machines with non-Windows\n  guest OSes support Hyper-V Enhanced Session mode.\n\n### Usage (Quick Start)\n\n- Move SynthRdp.exe to \"%SystemDrive%\\Windows\\System32\" folder in your virtual\n  machine which needs to use SynthRdp. The platform of SynthRdp.exe needs to be\n  the same as the virtual machine guest OS.\n- Open the Command Prompt as Administrator and execute the following commands.\n  ```\n  SynthRdp Install\n  SynthRdp Config Set DisableRemoteDesktop False\n  SynthRdp Config Set EnableUserAuthentication False\n  SynthRdp Config Set DisableBlankPassword False\n  ```\n\n### Usage (Detailed)\n\n```\nFormat: SynthRdp [Command] <Option1> <Option2> ...\n\nCommands:\n\n  Help - Show this content.\n\n  Install - Install SynthRdp service.\n  Uninstall - Uninstall SynthRdp service.\n  Start - Start SynthRdp service.\n  Stop - Stop SynthRdp service.\n\n  Config List - List all configurations related to SynthRdp.\n  Config Set [Key] <Value> - Set the specific configuration\n                             with the specific value, or reset\n                             the specific configuration if you\n                             don't specify the value.\n\nConfiguration Keys:\n\n  DisableRemoteDesktop <True|False>\n    Set False to enable the remote desktop for this virtual\n    machine. The default setting is True. Remote Desktop is\n    necessary for the Hyper-V Enhanced Session because it is\n    actually the RDP connection over the VMBus pipe.\n  EnableUserAuthentication <True|False>\n    Set False to allow connections without Network Level\n    Authentication. The default setting is True. Set this\n    configuration option False is necessary for using the\n    Hyper-V Enhanced Session via the SynthRdp service.\n  DisableBlankPassword <True|False>\n    Set False to enable the usage of logging on this virtual\n    machine as the account with the blank password via remote\n    desktop. The default setting is True. Set this\n    configuration option False will make you use the Hyper-V\n    Enhanced Session via the SynthRdp service happier, but\n    compromise the security.\n  OverrideSystemImplementation <True|False>\n    Set True to use the Hyper-V Enhanced Session via the\n    SynthRdp service on Windows 8.1 / Server 2012 R2 or later\n    guests which have the built-in Hyper-V Enhanced Session\n    support for this virtual machine. The default setting is\n    False. You can set this configuration option True if you\n    want to use your current virtual machine as the Hyper-V\n    Enhanced Session proxy server. You need to reboot your\n    virtual machine for applying this configuration option\n    change.\n  ServerHost <Host>\n    Set the server host for the remote desktop connection you\n    want to use in the Hyper-V Enhanced Session. The default\n    setting is 127.0.0.1.\n  ServerPort <Port>\n    Set the server port for the remote desktop connection you\n    want to use in the Hyper-V Enhanced Session. The default\n    setting is 3389.\n\nNotes:\n  - All command options are case-insensitive.\n  - SynthRdp will run as a console application instead of\n    service if you don't specify another command.\n\nExamples:\n\n  SynthRdp Install\n  SynthRdp Uninstall\n  SynthRdp Start\n  SynthRdp Stop\n\n  SynthRdp Config List\n\n  SynthRdp Config Set DisableRemoteDesktop False\n  SynthRdp Config Set EnableUserAuthentication False\n  SynthRdp Config Set DisableBlankPassword False\n  SynthRdp Config Set OverrideSystemImplementation False\n  SynthRdp Config Set ServerHost 127.0.0.1\n  SynthRdp Config Set ServerPort 3389\n\n  SynthRdp Config Set DisableRemoteDesktop\n  SynthRdp Config Set EnableUserAuthentication\n  SynthRdp Config Set DisableBlankPassword\n  SynthRdp Config Set OverrideSystemImplementation\n  SynthRdp Config Set ServerHost\n  SynthRdp Config Set ServerPort\n```\n\n### Suggestions\n\n- Users should use the SynthRdp to connect to Windows Vista or later guests for\n  decent user experiences.\n"
  },
  {
    "path": "SynthRdp/AutoRun.inf",
    "content": "[autorun]\nopen=SynthRdpInstaller.exe\nicon=SynthRdpInstaller.exe\nlabel=Hyper-V Enhanced Session Proxy Service (SynthRdp)"
  },
  {
    "path": "SynthRdp/SynthRdp.cpp",
    "content": "﻿/*\n * PROJECT:    NanaRun\n * FILE:       SynthRdp.cpp\n * PURPOSE:    Implementation for Hyper-V Enhanced Session Proxy Service\n *\n * LICENSE:    The MIT License\n *\n * MAINTAINER: MouriNaruto (Kenji.Mouri@outlook.com)\n */\n\n#define _WINSOCKAPI_\n#include <Windows.h>\n\n#include <WinSock2.h>\n#include <WS2tcpip.h>\n#pragma comment(lib, \"Ws2_32.lib\")\n\n#include <Mile.Helpers.CppBase.h>\n\n#include <Mile.HyperV.VMBus.h>\n#include <Mile.HyperV.Windows.VMBusPipe.h>\n\n#include <Mile.Project.Version.h>\n\nEXTERN_C HANDLE WINAPI VmbusPipeClientTryOpenChannel(\n    _In_ LPCGUID InterfaceType,\n    _In_ LPCGUID InterfaceInstance,\n    _In_ DWORD TimeoutInMsec,\n    _In_ DWORD OpenMode)\n{\n    VMBUS_PIPE_CHANNEL_INFO ChannelInfo = { 0 };\n    if (::VmbusPipeClientWaitChannel(\n        InterfaceType,\n        InterfaceInstance,\n        TimeoutInMsec,\n        &ChannelInfo))\n    {\n        return ::VmbusPipeClientOpenChannel(\n            &ChannelInfo,\n            OpenMode);\n    }\n\n    return INVALID_HANDLE_VALUE;\n}\n\nnamespace\n{\n    static SERVICE_STATUS_HANDLE volatile g_ServiceStatusHandle = nullptr;\n    static bool volatile g_ServiceIsRunning = true;\n    static bool volatile g_InteractiveMode = false;\n}\n\nSOCKET SynthRdpConnectToServer()\n{\n    SOCKET Result = INVALID_SOCKET;\n\n    std::string ServerHost = \"127.0.0.1\";\n    {\n        std::wstring Buffer(32767, L'\\0');\n        DWORD Length = static_cast<DWORD>(Buffer.size());\n        if (ERROR_SUCCESS == ::RegGetValueW(\n            HKEY_LOCAL_MACHINE,\n            L\"SYSTEM\\\\CurrentControlSet\\\\Services\\\\\"\n            L\"SynthRdp\\\\Configurations\",\n            L\"ServerHost\",\n            RRF_RT_REG_SZ | RRF_SUBKEY_WOW6464KEY,\n            nullptr,\n            const_cast<wchar_t*>(Buffer.c_str()),\n            &Length))\n        {\n            Buffer.resize(std::wcslen(Buffer.c_str()));\n            ServerHost = Mile::ToString(CP_UTF8, Buffer);\n        }\n    }\n\n    std::string ServerPort = \"3389\";\n    {\n        DWORD Data = 0;\n        DWORD Length = sizeof(DWORD);\n        if (ERROR_SUCCESS == ::RegGetValueW(\n            HKEY_LOCAL_MACHINE,\n            L\"SYSTEM\\\\CurrentControlSet\\\\Services\\\\\"\n            L\"SynthRdp\\\\Configurations\",\n            L\"ServerPort\",\n            RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY,\n            nullptr,\n            &Data,\n            &Length))\n        {\n            ServerPort = Mile::FormatString(\"%hu\", Data);\n        }\n    }\n\n    int LastError = 0;\n\n    addrinfo AddressHints = { 0 };\n    AddressHints.ai_family = AF_INET;\n    AddressHints.ai_socktype = SOCK_STREAM;\n    AddressHints.ai_protocol = IPPROTO_TCP;\n    addrinfo* AddressInfo = nullptr;\n    LastError = ::getaddrinfo(\n        ServerHost.c_str(),\n        ServerPort.c_str(),\n        &AddressHints,\n        &AddressInfo);\n    if (0 == LastError)\n    {\n        for (addrinfo* Current = AddressInfo;\n            nullptr != Current;\n            Current = Current->ai_next)\n        {\n            SOCKET Socket = ::WSASocketW(\n                Current->ai_family,\n                Current->ai_socktype,\n                Current->ai_protocol,\n                nullptr,\n                0,\n                WSA_FLAG_OVERLAPPED);\n            if (INVALID_SOCKET == Socket)\n            {\n                LastError = ::WSAGetLastError();\n                continue;\n            }\n\n            if (SOCKET_ERROR != ::WSAConnect(\n                Socket,\n                Current->ai_addr,\n                static_cast<int>(Current->ai_addrlen),\n                nullptr,\n                nullptr,\n                nullptr,\n                nullptr))\n            {\n                Result = Socket;\n                break;\n            }\n\n            LastError = ::WSAGetLastError();\n            ::closesocket(Socket);\n        }\n\n        ::freeaddrinfo(AddressInfo);\n    }\n\n    if (INVALID_SOCKET == Result && 0 != LastError)\n    {\n        ::WSASetLastError(LastError);\n    }\n\n    return Result;\n}\n\nstruct SynthRdpServiceConnectionContext\n{\n    std::uint8_t SendBuffer[16384];\n    std::uint8_t RecvBuffer[16384];\n};\n\nvoid SynthRdpRedirectionWorker(\n    _In_ HANDLE PipeHandle)\n{\n    SOCKET Socket = INVALID_SOCKET;\n    SynthRdpServiceConnectionContext* Context = nullptr;\n\n    do\n    {\n        Socket = ::SynthRdpConnectToServer();\n        if (Socket == INVALID_SOCKET)\n        {\n            if (g_InteractiveMode)\n            {\n                std::printf(\n                    \"[Error] SynthRdpConnectToServer failed (%d).\\n\",\n                    ::WSAGetLastError());\n            }\n            break;\n        }\n\n        Context = reinterpret_cast<SynthRdpServiceConnectionContext*>(\n            ::MileAllocateMemory(sizeof(SynthRdpServiceConnectionContext)));\n        if (!Context)\n        {\n            if (g_InteractiveMode)\n            {\n                std::printf(\n                    \"[Error] MileAllocateMemory failed.\\n\");\n            }\n            break;\n        }\n\n        // X.224 Connection Request PDU (Patched)\n        {\n            DWORD NumberOfBytesRead = 0;\n            if (!::MileReadFile(\n                PipeHandle,\n                Context->SendBuffer,\n                static_cast<DWORD>(sizeof(Context->SendBuffer)),\n                &NumberOfBytesRead))\n            {\n                if (g_InteractiveMode)\n                {\n                    std::printf(\n                        \"[Error] MileReadFile failed (%d).\\n\",\n                        ::GetLastError());\n                }\n                break;\n            }\n\n            // Set requestedProtocols to PROTOCOL_RDP (0x00000000).\n            Context->SendBuffer[15] = 0x00;\n\n            if (g_InteractiveMode)\n            {\n                std::wprintf(\n                    L\"[Info] MileSocketSend: %d Bytes.\\n\",\n                    NumberOfBytesRead);\n            }\n\n            DWORD NumberOfBytesSent = 0;\n            DWORD Flags = 0;\n            if (!::MileSocketSend(\n                Socket,\n                Context->SendBuffer,\n                NumberOfBytesRead,\n                &NumberOfBytesSent,\n                Flags))\n            {\n                if (g_InteractiveMode)\n                {\n                    std::printf(\n                        \"[Error] MileSocketSend failed (%d).\\n\",\n                        ::WSAGetLastError());\n                }\n                break;\n            }\n        }\n\n        bool volatile ShouldRunning = true;\n\n        HANDLE Vmbus2TcpThread = Mile::CreateThread([&]()\n        {\n            for (; ShouldRunning && g_ServiceIsRunning;)\n            {\n                DWORD NumberOfBytesRead = 0;\n                if (!::MileReadFile(\n                    PipeHandle,\n                    Context->SendBuffer,\n                    static_cast<DWORD>(sizeof(Context->SendBuffer)),\n                    &NumberOfBytesRead))\n                {\n                    if (g_InteractiveMode)\n                    {\n                        std::printf(\n                            \"[Error] MileReadFile failed (%d).\\n\",\n                            ::GetLastError());\n                    }\n                    break;\n                }\n\n                if (g_InteractiveMode)\n                {\n                    std::printf(\n                        \"[Info] MileSocketSend: %d Bytes.\\n\",\n                        NumberOfBytesRead);\n                }\n\n                DWORD NumberOfBytesSent = 0;\n                DWORD Flags = 0;\n                if (!::MileSocketSend(\n                    Socket,\n                    Context->SendBuffer,\n                    NumberOfBytesRead,\n                    &NumberOfBytesSent,\n                    Flags))\n                {\n                    if (g_InteractiveMode)\n                    {\n                        std::printf(\n                            \"[Error] MileSocketSend failed (%d).\\n\",\n                            ::WSAGetLastError());\n                    }\n                    break;\n                }\n            }\n        });\n\n        HANDLE Tcp2VmbusThread = Mile::CreateThread([&]()\n        {\n            for (; ShouldRunning && g_ServiceIsRunning;)\n            {\n                DWORD NumberOfBytesRecvd = 0;\n                DWORD Flags = MSG_PARTIAL;\n                if (!::MileSocketRecv(\n                    Socket,\n                    Context->RecvBuffer,\n                    static_cast<DWORD>(sizeof(Context->RecvBuffer)),\n                    &NumberOfBytesRecvd,\n                    &Flags))\n                {\n                    if (g_InteractiveMode)\n                    {\n                        std::printf(\n                            \"[Error] MileSocketRecv failed (%d).\\n\",\n                            ::WSAGetLastError());\n                    }\n                    break;\n                }\n\n                if (g_InteractiveMode)\n                {\n                    std::printf(\n                        \"[Info] MileWriteFile: %d Bytes.\\n\",\n                        NumberOfBytesRecvd);\n                }\n\n                DWORD NumberOfBytesWritten = 0;\n                if (!::MileWriteFile(\n                    PipeHandle,\n                    Context->RecvBuffer,\n                    NumberOfBytesRecvd,\n                    &NumberOfBytesWritten))\n                {\n                    if (g_InteractiveMode)\n                    {\n                        std::printf(\n                            \"[Error] MileWriteFile failed (%d).\\n\",\n                            ::GetLastError());\n                    }\n                    break;\n                }\n            }\n        });\n\n        for (;;)\n        {\n            if (WAIT_TIMEOUT != ::WaitForSingleObject(\n                Vmbus2TcpThread,\n                100))\n            {\n                ShouldRunning = false;\n                break;\n            }\n\n            if (WAIT_TIMEOUT != ::WaitForSingleObject(\n                Tcp2VmbusThread,\n                100))\n            {\n                ShouldRunning = false;\n                break;\n            }\n        }\n\n        if (Vmbus2TcpThread)\n        {\n            ::CloseHandle(Vmbus2TcpThread);\n            Vmbus2TcpThread = nullptr;\n        }\n\n        if (Tcp2VmbusThread)\n        {\n            ::CloseHandle(Tcp2VmbusThread);\n            Tcp2VmbusThread = nullptr;\n        }\n\n    } while (false);\n\n    if (Context)\n    {\n        ::MileFreeMemory(Context);\n    }\n\n    if (Socket != INVALID_SOCKET)\n    {\n        ::closesocket(Socket);\n    }\n}\n\nDWORD SynthRdpMain()\n{\n    WSADATA WSAData = { 0 };\n    {\n        int WSAError = ::WSAStartup(MAKEWORD(2, 2), &WSAData);\n        if (NO_ERROR != WSAError)\n        {\n            if (g_InteractiveMode)\n            {\n                std::printf(\n                    \"[Error] WSAStartup failed (%d).\\n\",\n                    WSAError);\n            }\n            return WSAError;\n        }\n    }\n\n    DWORD Error = ERROR_SUCCESS;\n\n    HANDLE ControlChannelHandle = INVALID_HANDLE_VALUE;\n\n    do\n    {\n        ControlChannelHandle = ::VmbusPipeClientTryOpenChannel(\n            &SYNTHRDP_CONTROL_CLASS_ID,\n            &SYNTHRDP_CONTROL_INSTANCE_ID,\n            INFINITE,\n            FILE_FLAG_OVERLAPPED);\n        if (INVALID_HANDLE_VALUE == ControlChannelHandle)\n        {\n            Error = ::GetLastError();\n            if (g_InteractiveMode)\n            {\n                std::printf(\n                    \"[Error] VmbusPipeClientTryOpenChannel failed (%d).\\n\",\n                    Error);\n            }\n            break;\n        }\n\n        SYNTHRDP_VERSION_REQUEST_MESSAGE Request;\n        std::memset(\n            &Request,\n            0,\n            sizeof(SYNTHRDP_VERSION_REQUEST_MESSAGE));\n        Request.Header.Type = SynthrdpVersionRequest;\n        Request.Header.Size = 0;\n        Request.Version.AsDWORD = SYNTHRDP_VERSION_WINBLUE;\n        Request.Reserved = 0;\n        DWORD NumberOfBytesWritten = 0;\n        if (!::MileWriteFile(\n            ControlChannelHandle,\n            &Request,\n            sizeof(Request),\n            &NumberOfBytesWritten))\n        {\n            Error = ::GetLastError();\n            if (g_InteractiveMode)\n            {\n                std::printf(\n                    \"[Error] MileWriteFile failed (%d).\\n\",\n                    Error);\n            }\n            break;\n        }\n\n        if (sizeof(SYNTHRDP_VERSION_REQUEST_MESSAGE) != NumberOfBytesWritten)\n        {\n            Error = ERROR_INVALID_DATA;\n            if (g_InteractiveMode)\n            {\n                std::printf(\n                    \"[Error] SYNTHRDP_VERSION_REQUEST_MESSAGE Invalid.\\n\");\n            }\n            break;\n        }\n\n        SYNTHRDP_VERSION_RESPONSE_MESSAGE Response;\n        std::memset(\n            &Response,\n            0,\n            sizeof(SYNTHRDP_VERSION_RESPONSE_MESSAGE));\n        DWORD NumberOfBytesRead = 0;\n        if (!::MileReadFile(\n            ControlChannelHandle,\n            &Response,\n            sizeof(Response),\n            &NumberOfBytesRead))\n        {\n            Error = ::GetLastError();\n            if (g_InteractiveMode)\n            {\n                std::printf(\n                    \"[Error] MileReadFile failed (%d).\\n\",\n                    Error);\n            }\n            break;\n        }\n\n        if (sizeof(SYNTHRDP_VERSION_RESPONSE_MESSAGE) != NumberOfBytesRead ||\n            SYNTHRDP_TRUE_WITH_VERSION_EXCHANGE != Response.IsAccepted)\n        {\n            Error = ERROR_INVALID_DATA;\n            if (g_InteractiveMode)\n            {\n                std::printf(\n                    \"[Error] SYNTHRDP_VERSION_RESPONSE_MESSAGE Invalid.\\n\");\n            }\n            break;\n        }\n\n        GUID Instances[] =\n        {\n            SYNTHRDP_DATA_INSTANCE_ID_1,\n            SYNTHRDP_DATA_INSTANCE_ID_2,\n            SYNTHRDP_DATA_INSTANCE_ID_3,\n            SYNTHRDP_DATA_INSTANCE_ID_4,\n            SYNTHRDP_DATA_INSTANCE_ID_5\n        };\n        for (size_t i = 0; g_ServiceIsRunning; ++i)\n        {\n            HANDLE DataChannelHandle = ::VmbusPipeClientTryOpenChannel(\n                &SYNTHRDP_DATA_CLASS_ID,\n                &Instances[i % (sizeof(Instances) / sizeof(*Instances))],\n                50,\n                FILE_FLAG_OVERLAPPED);\n            if (INVALID_HANDLE_VALUE == DataChannelHandle)\n            {\n                continue;\n            }\n\n            ::SynthRdpRedirectionWorker(DataChannelHandle);\n\n            ::CloseHandle(DataChannelHandle);\n        }\n\n    } while (false);\n\n    if (INVALID_HANDLE_VALUE != ControlChannelHandle)\n    {\n        ::CloseHandle(ControlChannelHandle);\n    }\n\n    ::WSACleanup();\n\n    return Error;\n}\n\nnamespace\n{\n    std::wstring GetCurrentProcessModulePath()\n    {\n        // 32767 is the maximum path length without the terminating null\n        // character.\n        std::wstring Path(32767, L'\\0');\n        Path.resize(::GetModuleFileNameW(\n            nullptr, &Path[0], static_cast<DWORD>(Path.size())));\n        return Path;\n    }\n\n    static std::wstring g_ServiceName =\n        L\"SynthRdp\";\n    static std::wstring g_DisplayName =\n        L\"Hyper-V Enhanced Session Proxy Service\";\n}\n\nvoid WINAPI SynthRdpServiceHandler(\n    _In_ DWORD dwControl)\n{\n    switch (dwControl)\n    {\n    case SERVICE_CONTROL_STOP:\n    {\n        SERVICE_STATUS ServiceStatus = { 0 };\n        ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;\n        ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;\n        ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;\n        ServiceStatus.dwWin32ExitCode = ERROR_SUCCESS;\n        ServiceStatus.dwServiceSpecificExitCode = 0;\n        ServiceStatus.dwCheckPoint = 0;\n        ServiceStatus.dwWaitHint = 0;\n        ::SetServiceStatus(g_ServiceStatusHandle, &ServiceStatus);\n\n        g_ServiceIsRunning = false;\n\n        break;\n    }\n    default:\n        break;\n    }\n}\n\nvoid WINAPI SynthRdpServiceMain(\n    _In_ DWORD dwNumServicesArgs,\n    _In_ LPWSTR* lpServiceArgVectors)\n{\n    UNREFERENCED_PARAMETER(dwNumServicesArgs);\n    UNREFERENCED_PARAMETER(lpServiceArgVectors);\n\n    g_ServiceStatusHandle = ::RegisterServiceCtrlHandlerW(\n        g_ServiceName.c_str(),\n        ::SynthRdpServiceHandler);\n    if (g_ServiceStatusHandle)\n    {\n        SERVICE_STATUS ServiceStatus = { 0 };\n        ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;\n        ServiceStatus.dwCurrentState = SERVICE_RUNNING;\n        ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;\n        ServiceStatus.dwWin32ExitCode = ERROR_SUCCESS;\n        ServiceStatus.dwServiceSpecificExitCode = 0;\n        ServiceStatus.dwCheckPoint = 0;\n        ServiceStatus.dwWaitHint = 0;\n        if (::SetServiceStatus(g_ServiceStatusHandle, &ServiceStatus))\n        {\n            ServiceStatus.dwCurrentState = SERVICE_STOPPED;\n            ServiceStatus.dwControlsAccepted = 0;\n            ServiceStatus.dwWin32ExitCode = ::SynthRdpMain();\n            ::SetServiceStatus(g_ServiceStatusHandle, &ServiceStatus);\n        }\n    }\n}\n\nint SynthRdpInstallService()\n{\n    DWORD Error = ERROR_SUCCESS;\n\n    std::wstring ServiceBinaryPath =\n        ::GetCurrentProcessModulePath() + L\" Service\";\n\n    SC_HANDLE ServiceControlManagerHandle = ::OpenSCManagerW(\n        nullptr,\n        nullptr,\n        SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);\n    if (ServiceControlManagerHandle)\n    {\n        SC_HANDLE ServiceHandle = ::CreateServiceW(\n            ServiceControlManagerHandle,\n            g_ServiceName.c_str(),\n            g_DisplayName.c_str(),\n            SERVICE_QUERY_STATUS | SERVICE_START,\n            SERVICE_WIN32_OWN_PROCESS,\n            SERVICE_AUTO_START,\n            SERVICE_ERROR_NORMAL,\n            ServiceBinaryPath.c_str(),\n            nullptr,\n            nullptr,\n            nullptr,\n            nullptr,\n            nullptr);\n        if (ServiceHandle)\n        {\n            SERVICE_STATUS_PROCESS ServiceStatus = { 0 };\n            if (!::MileStartServiceByHandle(\n                ServiceHandle,\n                0,\n                nullptr,\n                &ServiceStatus))\n            {\n                Error = ::GetLastError();\n            }\n\n            ::CloseServiceHandle(ServiceHandle);\n        }\n        else\n        {\n            Error = ::GetLastError();\n        }\n\n        ::CloseServiceHandle(ServiceControlManagerHandle);\n    }\n    else\n    {\n        Error = ::GetLastError();\n    }\n\n    if (ERROR_SUCCESS == Error)\n    {\n        std::printf(\"[Success] SynthRdpInstallService\\n\");\n    }\n    else\n    {\n        std::printf(\"[Error] SynthRdpInstallService (%d)\\n\", Error);\n    }\n\n    return Error;\n}\n\nint SynthRdpUninstallService()\n{\n    DWORD Error = ERROR_SUCCESS;\n\n    SC_HANDLE ServiceControlManagerHandle = ::OpenSCManagerW(\n        nullptr,\n        nullptr,\n        SC_MANAGER_CONNECT);\n    if (ServiceControlManagerHandle)\n    {\n        SC_HANDLE ServiceHandle = ::OpenServiceW(\n            ServiceControlManagerHandle,\n            g_ServiceName.c_str(),\n            SERVICE_QUERY_STATUS | SERVICE_STOP | DELETE);\n        if (ServiceHandle)\n        {\n            SERVICE_STATUS_PROCESS ServiceStatus = { 0 };\n            if (::MileStopServiceByHandle(ServiceHandle, &ServiceStatus))\n            {\n                if (!::DeleteService(ServiceHandle))\n                {\n                    Error = ::GetLastError();\n                }\n            }\n            else\n            {\n                Error = ::GetLastError();\n            }\n\n            ::CloseServiceHandle(ServiceHandle);\n        }\n        else\n        {\n            Error = ::GetLastError();\n        }\n\n        ::CloseServiceHandle(ServiceControlManagerHandle);\n    }\n    else\n    {\n        Error = ::GetLastError();\n    }\n\n    if (ERROR_SUCCESS == Error)\n    {\n        std::printf(\"[Success] SynthRdpUninstallService\\n\");\n    }\n    else\n    {\n        std::printf(\"[Error] SynthRdpUninstallService (%d)\\n\", Error);\n    }\n\n    return Error;\n}\n\nint SynthRdpStartService()\n{\n    DWORD Error = ERROR_SUCCESS;\n\n    SERVICE_STATUS_PROCESS ServiceStatus = { 0 };\n    if (!::MileStartService(g_ServiceName.c_str(), &ServiceStatus))\n    {\n        Error = ::GetLastError();\n    }\n\n    if (ERROR_SUCCESS == Error)\n    {\n        std::printf(\"[Success] SynthRdpStartService\\n\");\n    }\n    else\n    {\n        std::printf(\"[Error] SynthRdpStartService (%d)\\n\", Error);\n    }\n\n    return Error;\n}\n\nint SynthRdpStopService()\n{\n    DWORD Error = ERROR_SUCCESS;\n\n    SERVICE_STATUS_PROCESS ServiceStatus = { 0 };\n    if (!::MileStopService(g_ServiceName.c_str(), &ServiceStatus))\n    {\n        Error = ::GetLastError();\n    }\n\n    if (ERROR_SUCCESS == Error)\n    {\n        std::printf(\"[Success] SynthRdpStopService\\n\");\n    }\n    else\n    {\n        std::printf(\"[Error] SynthRdpStopService (%d)\\n\", Error);\n    }\n\n    return Error;\n}\n\nint SynthRdpListConfigurations()\n{\n    DWORD Error = ERROR_SUCCESS;\n\n    DWORD Data = 0;\n    DWORD Length = 0;\n\n    bool DisableRemoteDesktop = false;\n    {\n        Data = 0;\n        Length = sizeof(DWORD);\n        Error = ::RegGetValueW(\n            HKEY_LOCAL_MACHINE,\n            L\"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Terminal Server\",\n            L\"fDenyTSConnections\",\n            RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY,\n            nullptr,\n            &Data,\n            &Length);\n        if (ERROR_SUCCESS == Error)\n        {\n            DisableRemoteDesktop = Data;\n        }\n    }\n\n    bool EnableUserAuthentication = true;\n    {\n        Data = 0;\n        Length = sizeof(DWORD);\n        Error = ::RegGetValueW(\n            HKEY_LOCAL_MACHINE,\n            L\"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Terminal Server\\\\\"\n            L\"WinStations\\\\RDP-Tcp\",\n            L\"UserAuthentication\",\n            RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY,\n            nullptr,\n            &Data,\n            &Length);\n        if (ERROR_SUCCESS == Error)\n        {\n            EnableUserAuthentication = Data;\n        }\n    }\n\n    bool DisableBlankPassword = false;\n    {\n        Data = 0;\n        Length = sizeof(DWORD);\n        Error = ::RegGetValueW(\n            HKEY_LOCAL_MACHINE,\n            L\"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Lsa\",\n            L\"LimitBlankPasswordUse\",\n            RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY,\n            nullptr,\n            &Data,\n            &Length);\n        if (ERROR_SUCCESS == Error)\n        {\n            DisableBlankPassword = Data;\n        }\n    }\n\n    bool OverrideSystemImplementation = false;\n    {\n        Data = 0;\n        Length = sizeof(DWORD);\n        Error = ::RegGetValueW(\n            HKEY_LOCAL_MACHINE,\n            L\"SOFTWARE\\\\Microsoft\\\\Virtual Machine\\\\Guest\",\n            L\"DisableEnhancedSessionConsoleConnection\",\n            RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY,\n            nullptr,\n            &Data,\n            &Length);\n        if (ERROR_SUCCESS == Error)\n        {\n            OverrideSystemImplementation = Data;\n        }\n    }\n\n    std::string ServerHost = \"127.0.0.1\";\n    {\n        std::wstring Buffer(32767, L'\\0');\n\n        Length = static_cast<DWORD>(Buffer.size());\n        Error = ::RegGetValueW(\n            HKEY_LOCAL_MACHINE,\n            L\"SYSTEM\\\\CurrentControlSet\\\\Services\\\\\"\n            L\"SynthRdp\\\\Configurations\",\n            L\"ServerHost\",\n            RRF_RT_REG_SZ | RRF_SUBKEY_WOW6464KEY,\n            nullptr,\n            const_cast<wchar_t*>(Buffer.c_str()),\n            &Length);\n        if (ERROR_SUCCESS == Error)\n        {\n            Buffer.resize(std::wcslen(Buffer.c_str()));\n            ServerHost = Mile::ToString(CP_UTF8, Buffer);\n        }\n    }\n\n    std::uint16_t ServerPort = 3389;\n    {\n        Data = 0;\n        Length = sizeof(DWORD);\n        Error = ::RegGetValueW(\n            HKEY_LOCAL_MACHINE,\n            L\"SYSTEM\\\\CurrentControlSet\\\\Services\\\\\"\n            L\"SynthRdp\\\\Configurations\",\n            L\"ServerPort\",\n            RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY,\n            nullptr,\n            &Data,\n            &Length);\n        if (ERROR_SUCCESS == Error)\n        {\n            ServerPort = static_cast<std::uint16_t>(Data);\n        }\n    }\n\n    std::printf(\n        \"Configurations:\\n\"\n        \"\\n\"\n        \"DisableRemoteDesktop: %s\\n\"\n        \"EnableUserAuthentication: %s\\n\"\n        \"DisableBlankPassword: %s\\n\"\n        \"OverrideSystemImplementation: %s\\n\"\n        \"ServerHost: %s\\n\"\n        \"ServerPort: %hu\\n\"\n        \"\\n\",\n        DisableRemoteDesktop ? \"True\" : \"False\",\n        EnableUserAuthentication ? \"True\" : \"False\",\n        DisableBlankPassword ? \"True\" : \"False\",\n        OverrideSystemImplementation ? \"True\" : \"False\",\n        ServerHost.c_str(),\n        ServerPort);\n\n    return Error;\n}\n\nint SynthRdpUpdateConfiguration(\n    std::string const& Key,\n    std::string const& Value)\n{\n    DWORD Error = ERROR_SUCCESS;\n\n    if (0 == ::_stricmp(Key.c_str(), \"DisableRemoteDesktop\"))\n    {\n        DWORD Data = 1;\n        if (Value.empty() ||\n            0 == ::_stricmp(Value.c_str(), \"True\"))\n        {\n            // Use the default value.\n        }\n        else if (0 == ::_stricmp(Value.c_str(), \"False\"))\n        {\n            Data = 0;\n        }\n        else\n        {\n            Error = ERROR_INVALID_PARAMETER;\n        }\n\n        if (ERROR_SUCCESS == Error)\n        {\n            Error = ::RegSetKeyValueW(\n                HKEY_LOCAL_MACHINE,\n                L\"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Terminal Server\",\n                L\"fDenyTSConnections\",\n                REG_DWORD,\n                &Data,\n                sizeof(DWORD));\n        }\n    }\n    else if (0 == ::_stricmp(Key.c_str(), \"EnableUserAuthentication\"))\n    {\n        DWORD Data = 1;\n        if (Value.empty() ||\n            0 == ::_stricmp(Value.c_str(), \"True\"))\n        {\n            // Use the default value.\n        }\n        else if (0 == ::_stricmp(Value.c_str(), \"False\"))\n        {\n            Data = 0;\n        }\n        else\n        {\n            Error = ERROR_INVALID_PARAMETER;\n        }\n\n        if (ERROR_SUCCESS == Error)\n        {\n            Error = ::RegSetKeyValueW(\n                HKEY_LOCAL_MACHINE,\n                L\"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Terminal Server\\\\\"\n                L\"WinStations\\\\RDP-Tcp\",\n                L\"UserAuthentication\",\n                REG_DWORD,\n                &Data,\n                sizeof(DWORD));\n        }\n    }\n    else if (0 == ::_stricmp(Key.c_str(), \"DisableBlankPassword\"))\n    {\n        DWORD Data = 1;\n        if (Value.empty() ||\n            0 == ::_stricmp(Value.c_str(), \"True\"))\n        {\n            // Use the default value.\n        }\n        else if (0 == ::_stricmp(Value.c_str(), \"False\"))\n        {\n            Data = 0;\n        }\n        else\n        {\n            Error = ERROR_INVALID_PARAMETER;\n        }\n\n        if (ERROR_SUCCESS == Error)\n        {\n            Error = ::RegSetKeyValueW(\n                HKEY_LOCAL_MACHINE,\n                L\"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Lsa\",\n                L\"LimitBlankPasswordUse\",\n                REG_DWORD,\n                &Data,\n                sizeof(DWORD));\n        }\n    }\n    else if (0 == ::_stricmp(Key.c_str(), \"OverrideSystemImplementation\"))\n    {\n        if (Value.empty() ||\n            0 == ::_stricmp(Value.c_str(), \"False\"))\n        {\n            Error = ::RegDeleteKeyValueW(\n                HKEY_LOCAL_MACHINE,\n                L\"SOFTWARE\\\\Microsoft\\\\Virtual Machine\\\\Guest\",\n                L\"DisableEnhancedSessionConsoleConnection\");\n        }\n        else if (0 == ::_stricmp(Value.c_str(), \"True\"))\n        {\n            DWORD Data = 1;\n            Error = ::RegSetKeyValueW(\n                HKEY_LOCAL_MACHINE,\n                L\"SOFTWARE\\\\Microsoft\\\\Virtual Machine\\\\Guest\",\n                L\"DisableEnhancedSessionConsoleConnection\",\n                REG_DWORD,\n                &Data,\n                sizeof(DWORD));\n        }\n        else\n        {\n            Error = ERROR_INVALID_PARAMETER;\n        }\n    }\n    else if (0 == ::_stricmp(Key.c_str(), \"ServerHost\"))\n    {\n        if (Value.empty())\n        {\n            Error = ::RegDeleteKeyValueW(\n                HKEY_LOCAL_MACHINE,\n                L\"SYSTEM\\\\CurrentControlSet\\\\Services\\\\\"\n                L\"SynthRdp\\\\Configurations\",\n                L\"ServerHost\");\n        }\n        else\n        {\n            std::wstring ServerHost = Mile::ToWideString(CP_UTF8, Value);\n\n            Error = ::RegSetKeyValueW(\n                HKEY_LOCAL_MACHINE,\n                L\"SYSTEM\\\\CurrentControlSet\\\\Services\\\\\"\n                L\"SynthRdp\\\\Configurations\",\n                L\"ServerHost\",\n                REG_SZ,\n                ServerHost.c_str(),\n                static_cast<DWORD>((ServerHost.size() + 1) * sizeof(wchar_t)));\n        }\n    }\n    else if (0 == ::_stricmp(Key.c_str(), \"ServerPort\"))\n    {\n        if (Value.empty())\n        {\n            Error = ::RegDeleteKeyValueW(\n                HKEY_LOCAL_MACHINE,\n                L\"SYSTEM\\\\CurrentControlSet\\\\Services\\\\SynthRdp\\\\Configurations\",\n                L\"ServerPort\");\n        }\n        else\n        {\n            DWORD Data = static_cast<std::uint16_t>(Mile::ToUInt32(Value));\n            Error = ::RegSetKeyValueW(\n                HKEY_LOCAL_MACHINE,\n                L\"SYSTEM\\\\CurrentControlSet\\\\Services\\\\SynthRdp\\\\Configurations\",\n                L\"ServerPort\",\n                REG_DWORD,\n                &Data,\n                sizeof(DWORD));\n        }\n    }\n    else\n    {\n        Error = ERROR_INVALID_PARAMETER;\n    }\n\n    if (ERROR_SUCCESS == Error)\n    {\n        std::printf(\n            \"[Success] SynthRdpUpdateConfiguration %s\\n\",\n            Key.c_str());\n    }\n    else\n    {\n        std::printf(\n            \"[Error] SynthRdpUpdateConfiguration %s (%d)\\n\",\n            Key.c_str(),\n            Error);\n    }\n\n    return Error;\n}\n\nint main()\n{\n    ::std::printf(\n        \"SynthRdp \" MILE_PROJECT_VERSION_UTF8_STRING \" (Build \"\n        MILE_PROJECT_MACRO_TO_UTF8_STRING(MILE_PROJECT_VERSION_BUILD) \")\" \"\\n\"\n        \"(c) M2-Team and Contributors. All rights reserved.\\n\"\n        \"\\n\");\n\n    std::vector<std::string> Arguments = Mile::SplitCommandLineString(\n        Mile::ToString(CP_UTF8, ::GetCommandLineW()));\n\n    bool NeedParse = (Arguments.size() > 1);\n\n    if (!NeedParse)\n    {\n        g_InteractiveMode = true;\n\n        std::printf(\n            \"[Info] SynthRdp will run as a console application instead of \"\n            \"service.\\n\"\n            \"[Info] Use \\\"SynthRdp Help\\\" for more commands.\\n\"\n            \"\\n\");\n\n        return ::SynthRdpMain();\n    }\n\n    int Result = 0;\n\n    bool ParseError = false;\n    bool ShowHelp = false;\n\n    if (0 == ::_stricmp(Arguments[1].c_str(), \"Help\"))\n    {\n        ShowHelp = true;\n    }\n    else if (0 == ::_stricmp(Arguments[1].c_str(), \"Service\"))\n    {\n        ::FreeConsole();\n\n        SERVICE_TABLE_ENTRYW ServiceStartTable[] =\n        {\n            {\n                const_cast<wchar_t*>(g_ServiceName.c_str()),\n                ::SynthRdpServiceMain\n            }\n        };\n\n        return ::StartServiceCtrlDispatcherW(ServiceStartTable)\n            ? ERROR_SUCCESS :\n            ::GetLastError();\n    }\n    else if (0 == ::_stricmp(Arguments[1].c_str(), \"Install\"))\n    {\n        Result = ::SynthRdpInstallService();\n    }\n    else if (0 == ::_stricmp(Arguments[1].c_str(), \"Uninstall\"))\n    {\n        Result = ::SynthRdpUninstallService();\n    }\n    else if (0 == ::_stricmp(Arguments[1].c_str(), \"Start\"))\n    {\n        Result = ::SynthRdpStartService();\n    }\n    else if (0 == ::_stricmp(Arguments[1].c_str(), \"Stop\"))\n    {\n        Result = ::SynthRdpStopService();\n    }\n    else if (0 == ::_stricmp(Arguments[1].c_str(), \"Config\"))\n    {\n        ParseError = !(Arguments.size() > 2);\n        if (!ParseError)\n        {\n            if (0 == ::_stricmp(Arguments[2].c_str(), \"List\"))\n            {\n                Result = ::SynthRdpListConfigurations();\n            }\n            else if (0 == ::_stricmp(Arguments[2].c_str(), \"Set\"))\n            {\n                ParseError = !(Arguments.size() > 3);\n                if (!ParseError)\n                {\n                    Result = ::SynthRdpUpdateConfiguration(\n                        Arguments[3],\n                        (Arguments.size() > 4) ? Arguments[4] : std::string());\n                }\n            }\n        }\n    }\n    else\n    {\n        ParseError = true;\n    }\n\n    if (ParseError)\n    {\n        std::printf(\n            \"[Error] Unrecognized command.\\n\"\n            \"\\n\");\n    }\n\n    if (ParseError || ShowHelp)\n    {\n        std::printf(\n            \"Format: SynthRdp [Command] <Option1> <Option2> ...\\n\"\n            \"\\n\"\n            \"Commands:\\n\"\n            \"\\n\"\n            \"  Help - Show this content.\\n\"\n            \"\\n\"\n            \"  Install - Install SynthRdp service.\\n\"\n            \"  Uninstall - Uninstall SynthRdp service.\\n\"\n            \"  Start - Start SynthRdp service.\\n\"\n            \"  Stop - Stop SynthRdp service.\\n\"\n            \"\\n\"\n            \"  Config List - List all configurations related to SynthRdp.\\n\"\n            \"  Config Set [Key] <Value> - Set the specific configuration\\n\"\n            \"                             with the specific value, or reset\\n\"\n            \"                             the specific configuration if you\\n\"\n            \"                             don't specify the value.\\n\"\n            \"\\n\"\n            \"Configuration Keys:\\n\"\n            \"\\n\"\n            \"  DisableRemoteDesktop <True|False>\\n\"\n            \"    Set False to enable the remote desktop for this virtual\\n\"\n            \"    machine. The default setting is True. Remote Desktop is\\n\"\n            \"    necessary for the Hyper-V Enhanced Session because it is\\n\"\n            \"    actually the RDP connection over the VMBus pipe.\\n\"\n            \"  EnableUserAuthentication <True|False>\\n\"\n            \"    Set False to allow connections without Network Level\\n\"\n            \"    Authentication. The default setting is True. Set this\\n\"\n            \"    configuration option False is necessary for using the\\n\"\n            \"    Hyper-V Enhanced Session via the SynthRdp service.\\n\"\n            \"  DisableBlankPassword <True|False>\\n\"\n            \"    Set False to enable the usage of logging on this virtual\\n\"\n            \"    machine as the account with the blank password via remote\\n\"\n            \"    desktop. The default setting is True. Set this\\n\"\n            \"    configuration option False will make you use the Hyper-V\\n\"\n            \"    Enhanced Session via the SynthRdp service happier, but\\n\"\n            \"    compromise the security.\\n\"\n            \"  OverrideSystemImplementation <True|False>\\n\"\n            \"    Set True to use the Hyper-V Enhanced Session via the\\n\"\n            \"    SynthRdp service on Windows 8.1 / Server 2012 R2 or later\\n\"\n            \"    guests which have the built-in Hyper-V Enhanced Session\\n\"\n            \"    support for this virtual machine. The default setting is\\n\"\n            \"    False. You can set this configuration option True if you\\n\"\n            \"    want to use your current virtual machine as the Hyper-V\\n\"\n            \"    Enhanced Session proxy server. You need to reboot your\\n\"\n            \"    virtual machine for applying this configuration option\\n\"\n            \"    change.\\n\"\n            \"  ServerHost <Host>\\n\"\n            \"    Set the server host for the remote desktop connection you\\n\"\n            \"    want to use in the Hyper-V Enhanced Session. The default\\n\"\n            \"    setting is 127.0.0.1.\\n\"\n            \"  ServerPort <Port>\\n\"\n            \"    Set the server port for the remote desktop connection you\\n\"\n            \"    want to use in the Hyper-V Enhanced Session. The default\\n\"\n            \"    setting is 3389.\\n\"\n            \"\\n\"\n            \"Notes:\\n\"\n            \"  - All command options are case-insensitive.\\n\"\n            \"  - SynthRdp will run as a console application instead of\\n\"\n            \"    service if you don't specify another command.\\n\"\n            \"\\n\"\n            \"Examples:\\n\"\n            \"\\n\"\n            \"  SynthRdp Install\\n\"\n            \"  SynthRdp Uninstall\\n\"\n            \"  SynthRdp Start\\n\"\n            \"  SynthRdp Stop\\n\"\n            \"\\n\"\n            \"  SynthRdp Config List\\n\"\n            \"\\n\"\n            \"  SynthRdp Config Set DisableRemoteDesktop False\\n\"\n            \"  SynthRdp Config Set EnableUserAuthentication False\\n\"\n            \"  SynthRdp Config Set DisableBlankPassword False\\n\"\n            \"  SynthRdp Config Set OverrideSystemImplementation False\\n\"\n            \"  SynthRdp Config Set ServerHost 127.0.0.1\\n\"\n            \"  SynthRdp Config Set ServerPort 3389\\n\"\n            \"\\n\"\n            \"  SynthRdp Config Set DisableRemoteDesktop\\n\"\n            \"  SynthRdp Config Set EnableUserAuthentication\\n\"\n            \"  SynthRdp Config Set DisableBlankPassword\\n\"\n            \"  SynthRdp Config Set OverrideSystemImplementation\\n\"\n            \"  SynthRdp Config Set ServerHost\\n\"\n            \"  SynthRdp Config Set ServerPort\\n\"\n            \"\\n\");\n    }\n\n    return Result;\n}\n"
  },
  {
    "path": "SynthRdp/SynthRdp.iss",
    "content": "; -- 64BitThreeArch.iss --\n; Demonstrates how to install a program built for three different\n; architectures (x86, x64, Arm64) using a single installer.\n\n; SEE THE DOCUMENTATION FOR DETAILS ON CREATING .ISS SCRIPT FILES!\n\n[Setup]\nAppName=Hyper-V Enhanced Session Proxy Service (SynthRdp)\nAppVersion=1.0.92.0\nAppPublisher=M2-Team\nAppPublisherURL=https://github.com/M2Team/NanaRun\nWizardStyle=modern\nDefaultDirName={autopf}\\M2-Team\\NanaRun\nDefaultGroupName=NanaRun\nUninstallDisplayIcon={app}\\SynthRdp.exe\nCompression=lzma2\nSolidCompression=yes\nOutputDir=..\\Output\\SynthRdpInstallationImage\n; \"ArchitecturesInstallIn64BitMode=x64compatible or arm64\" instructs\n; Setup to use \"64-bit install mode\" on x64-compatible systems and\n; Arm64 systems, meaning Setup should use the native 64-bit Program\n; Files directory and the 64-bit view of the registry. On all other\n; OS architectures (e.g., 32-bit x86), Setup will use \"32-bit\n; install mode\".\nArchitecturesInstallIn64BitMode=x64compatible or arm64\nSetupLogging=yes\nOutputBaseFilename=SynthRdpInstaller\n\n[Files]\n; In order of preference, we want to install:\n; - Arm64 binaries on Arm64 systems\n; - else, x64 binaries on x64-compatible systems\n; - else, x86 binaries\n\n; Place all Arm64-specific files here, using 'Check: PreferArm64Files' on each entry.\nSource: \"..\\Output\\Binaries\\Release\\ARM64\\SynthRdp.exe\"; DestDir: \"{sysnative}\"; DestName: \"SynthRdp.exe\"; Check: PreferArm64Files\n\n; Place all x64-specific files here, using 'Check: PreferX64Files' on each entry.\n; Only the first entry should include the 'solidbreak' flag.\nSource: \"..\\Output\\Binaries\\Release\\x64\\SynthRdp.exe\"; DestDir: \"{sysnative}\"; DestName: \"SynthRdp.exe\"; Check: PreferX64Files; Flags: solidbreak\n\n; Place all x86-specific files here, using 'Check: PreferX86Files' on each entry.\n; Only the first entry should include the 'solidbreak' flag.\nSource: \"..\\Output\\Binaries\\Release\\Win32\\SynthRdp.exe\"; DestDir: \"{sysnative}\"; DestName: \"SynthRdp.exe\"; Check: PreferX86Files; Flags: solidbreak\n\n; Place all common files here.\n; Only the first entry should include the 'solidbreak' flag.\n;Source: \"MyProg.chm\"; DestDir: \"{app}\"; Flags: solidbreak\n;Source: \"Readme.txt\"; DestDir: \"{app}\"; Flags: isreadme\n\n[Code]\n\nfunction PreferArm64Files: Boolean;\nbegin\n  Result := IsArm64;\nend;\n\nfunction PreferX64Files: Boolean;\nbegin\n  Result := not PreferArm64Files and IsX64Compatible;\nend;\n\nfunction PreferX86Files: Boolean;\nbegin\n  Result := not PreferArm64Files and not PreferX64Files;\nend;\n\n[Run]\n\nFilename: \"{sysnative}\\SynthRdp.exe\"; Parameters: \"Uninstall\"; Flags: runhidden logoutput\nFilename: \"{sysnative}\\SynthRdp.exe\"; Parameters: \"Install\"; Flags: runhidden logoutput\nFilename: \"{sysnative}\\SynthRdp.exe\"; Parameters: \"Config Set DisableRemoteDesktop False\"; Flags: runhidden logoutput\nFilename: \"{sysnative}\\SynthRdp.exe\"; Parameters: \"Config Set EnableUserAuthentication False\"; Flags: runhidden logoutput\nFilename: \"{sysnative}\\SynthRdp.exe\"; Parameters: \"Config Set DisableBlankPassword False\"; Flags: runhidden logoutput\n\n[UninstallRun]\n\nFilename: \"{sysnative}\\SynthRdp.exe\"; Parameters: \"Uninstall\"; Flags: runhidden logoutput; RunOnceId: RemoveService"
  },
  {
    "path": "SynthRdp/SynthRdp.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n\t<compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n\t\t<application>\n\t\t\t<supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\"/>\n\t\t\t<supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>\n\t\t\t<supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n\t\t\t<supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>\n\t\t\t<supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>\n\t\t</application>\n\t</compatibility>\n</assembly>\n"
  },
  {
    "path": "SynthRdp/SynthRdp.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{ABFD05C2-4673-49EC-A23E-9CA53223EEC2}</ProjectGuid>\n    <RootNamespace>SynthRdp</RootNamespace>\n    <MileProjectType>ConsoleApplication</MileProjectType>\n    <MileProjectManifestFile>SynthRdp.manifest</MileProjectManifestFile>\n    <MileProjectEnableVCLTLSupport>true</MileProjectEnableVCLTLSupport>\n    <MileProjectUseProjectProperties>true</MileProjectUseProjectProperties>\n    <MileProjectCompanyName>M2-Team</MileProjectCompanyName>\n    <MileProjectFileDescription>Hyper-V Enhanced Session Proxy Service</MileProjectFileDescription>\n    <MileProjectInternalName>SynthRdp</MileProjectInternalName>\n    <MileProjectLegalCopyright>© M2-Team and Contributors. All rights reserved.</MileProjectLegalCopyright>\n    <MileProjectOriginalFilename>SynthRdp.exe</MileProjectOriginalFilename>\n    <MileProjectProductName>NanaRun</MileProjectProductName>\n    <MileProjectVersion>1.0.$([System.DateTime]::Today.Subtract($([System.DateTime]::Parse('2024-05-01'))).TotalDays).0</MileProjectVersion>\n    <MileProjectVersionTag>Preview 3</MileProjectVersionTag>\n    <MileHyperVEnableWindowsPlatformSupport>true</MileHyperVEnableWindowsPlatformSupport>\n    <WindowsTargetPlatformMinVersion>5.1.2600.0</WindowsTargetPlatformMinVersion>\n    <MileWindowsHelpersNoCppWinRTHelpers>true</MileWindowsHelpersNoCppWinRTHelpers>\n  </PropertyGroup>\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Platform.x86.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Platform.x64.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Platform.ARM64.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Cpp.Default.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Cpp.props\" />\n  <Import Project=\"..\\NanaRun.IconResource\\NanaRun.IconResource.props\" />\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <EnableEnhancedInstructionSet Condition=\"'$(Platform)'=='Win32'\">NoExtensions</EnableEnhancedInstructionSet>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"SynthRdp.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Manifest Include=\"SynthRdp.manifest\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Mile.Windows.Helpers\">\n      <Version>1.0.1171</Version>\n    </PackageReference>\n    <PackageReference Include=\"Mile.HyperV\">\n      <Version>1.2.907</Version>\n    </PackageReference>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"AutoRun.inf\" />\n    <None Include=\"SynthRdp.iss\" />\n  </ItemGroup>\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Cpp.targets\" />\n</Project>"
  },
  {
    "path": "Tools/Default.isl",
    "content": "﻿; *** Inno Setup version 6.1.0+ English messages ***\n;\n; To download user-contributed translations of this file, go to:\n;   https://jrsoftware.org/files/istrans/\n;\n; Note: When translating this text, do not add periods (.) to the end of\n; messages that didn't have them already, because on those messages Inno\n; Setup adds the periods automatically (appending a period would result in\n; two periods being displayed).\n\n[LangOptions]\n; The following three entries are very important. Be sure to read and \n; understand the '[LangOptions] section' topic in the help file.\nLanguageName=English\nLanguageID=$0409\nLanguageCodePage=0\n; If the language you are translating to requires special font faces or\n; sizes, uncomment any of the following entries and change them accordingly.\n;DialogFontName=\n;DialogFontSize=8\n;WelcomeFontName=Verdana\n;WelcomeFontSize=12\n;TitleFontName=Arial\n;TitleFontSize=29\n;CopyrightFontName=Arial\n;CopyrightFontSize=8\n\n[Messages]\n\n; *** Application titles\nSetupAppTitle=Setup\nSetupWindowTitle=Setup - %1\nUninstallAppTitle=Uninstall\nUninstallAppFullTitle=%1 Uninstall\n\n; *** Misc. common\nInformationTitle=Information\nConfirmTitle=Confirm\nErrorTitle=Error\n\n; *** SetupLdr messages\nSetupLdrStartupMessage=This will install %1. Do you wish to continue?\nLdrCannotCreateTemp=Unable to create a temporary file. Setup aborted\nLdrCannotExecTemp=Unable to execute file in the temporary directory. Setup aborted\nHelpTextNote=\n\n; *** Startup error messages\nLastErrorMessage=%1.%n%nError %2: %3\nSetupFileMissing=The file %1 is missing from the installation directory. Please correct the problem or obtain a new copy of the program.\nSetupFileCorrupt=The setup files are corrupted. Please obtain a new copy of the program.\nSetupFileCorruptOrWrongVer=The setup files are corrupted, or are incompatible with this version of Setup. Please correct the problem or obtain a new copy of the program.\nInvalidParameter=An invalid parameter was passed on the command line:%n%n%1\nSetupAlreadyRunning=Setup is already running.\nWindowsVersionNotSupported=This program does not support the version of Windows your computer is running.\nWindowsServicePackRequired=This program requires %1 Service Pack %2 or later.\nNotOnThisPlatform=This program will not run on %1.\nOnlyOnThisPlatform=This program must be run on %1.\nOnlyOnTheseArchitectures=This program can only be installed on versions of Windows designed for the following processor architectures:%n%n%1\nWinVersionTooLowError=This program requires %1 version %2 or later.\nWinVersionTooHighError=This program cannot be installed on %1 version %2 or later.\nAdminPrivilegesRequired=You must be logged in as an administrator when installing this program.\nPowerUserPrivilegesRequired=You must be logged in as an administrator or as a member of the Power Users group when installing this program.\nSetupAppRunningError=Setup has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit.\nUninstallAppRunningError=Uninstall has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit.\n\n; *** Startup questions\nPrivilegesRequiredOverrideTitle=Select Setup Install Mode\nPrivilegesRequiredOverrideInstruction=Select install mode\nPrivilegesRequiredOverrideText1=%1 can be installed for all users (requires administrative privileges), or for you only.\nPrivilegesRequiredOverrideText2=%1 can be installed for you only, or for all users (requires administrative privileges).\nPrivilegesRequiredOverrideAllUsers=Install for &all users\nPrivilegesRequiredOverrideAllUsersRecommended=Install for &all users (recommended)\nPrivilegesRequiredOverrideCurrentUser=Install for &me only\nPrivilegesRequiredOverrideCurrentUserRecommended=Install for &me only (recommended)\n\n; *** Misc. errors\nErrorCreatingDir=Setup was unable to create the directory \"%1\"\nErrorTooManyFilesInDir=Unable to create a file in the directory \"%1\" because it contains too many files\n\n; *** Setup common messages\nExitSetupTitle=Exit Setup\nExitSetupMessage=Setup is not complete. If you exit now, the program will not be installed.%n%nYou may run Setup again at another time to complete the installation.%n%nExit Setup?\nAboutSetupMenuItem=&About Setup...\nAboutSetupTitle=About Setup\nAboutSetupMessage=%1 version %2%n%3%n%n%1 home page:%n%4\nAboutSetupNote=\nTranslatorNote=\n\n; *** Buttons\nButtonBack=< &Back\nButtonNext=&Next >\nButtonInstall=&Install\nButtonOK=OK\nButtonCancel=Cancel\nButtonYes=&Yes\nButtonYesToAll=Yes to &All\nButtonNo=&No\nButtonNoToAll=N&o to All\nButtonFinish=&Finish\nButtonBrowse=&Browse...\nButtonWizardBrowse=B&rowse...\nButtonNewFolder=&Make New Folder\n\n; *** \"Select Language\" dialog messages\nSelectLanguageTitle=Select Setup Language\nSelectLanguageLabel=Select the language to use during the installation.\n\n; *** Common wizard text\nClickNext=Click Next to continue, or Cancel to exit Setup.\nBeveledLabel=\nBrowseDialogTitle=Browse For Folder\nBrowseDialogLabel=Select a folder in the list below, then click OK.\nNewFolderName=New Folder\n\n; *** \"Welcome\" wizard page\nWelcomeLabel1=Welcome to the [name] Setup Wizard\nWelcomeLabel2=This will install [name/ver] on your computer.%n%nIt is recommended that you close all other applications before continuing.\n\n; *** \"Password\" wizard page\nWizardPassword=Password\nPasswordLabel1=This installation is password protected.\nPasswordLabel3=Please provide the password, then click Next to continue. Passwords are case-sensitive.\nPasswordEditLabel=&Password:\nIncorrectPassword=The password you entered is not correct. Please try again.\n\n; *** \"License Agreement\" wizard page\nWizardLicense=License Agreement\nLicenseLabel=Please read the following important information before continuing.\nLicenseLabel3=Please read the following License Agreement. You must accept the terms of this agreement before continuing with the installation.\nLicenseAccepted=I &accept the agreement\nLicenseNotAccepted=I &do not accept the agreement\n\n; *** \"Information\" wizard pages\nWizardInfoBefore=Information\nInfoBeforeLabel=Please read the following important information before continuing.\nInfoBeforeClickLabel=When you are ready to continue with Setup, click Next.\nWizardInfoAfter=Information\nInfoAfterLabel=Please read the following important information before continuing.\nInfoAfterClickLabel=When you are ready to continue with Setup, click Next.\n\n; *** \"User Information\" wizard page\nWizardUserInfo=User Information\nUserInfoDesc=Please enter your information.\nUserInfoName=&User Name:\nUserInfoOrg=&Organization:\nUserInfoSerial=&Serial Number:\nUserInfoNameRequired=You must enter a name.\n\n; *** \"Select Destination Location\" wizard page\nWizardSelectDir=Select Destination Location\nSelectDirDesc=Where should [name] be installed?\nSelectDirLabel3=Setup will install [name] into the following folder.\nSelectDirBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse.\nDiskSpaceGBLabel=At least [gb] GB of free disk space is required.\nDiskSpaceMBLabel=At least [mb] MB of free disk space is required.\nCannotInstallToNetworkDrive=Setup cannot install to a network drive.\nCannotInstallToUNCPath=Setup cannot install to a UNC path.\nInvalidPath=You must enter a full path with drive letter; for example:%n%nC:\\APP%n%nor a UNC path in the form:%n%n\\\\server\\share\nInvalidDrive=The drive or UNC share you selected does not exist or is not accessible. Please select another.\nDiskSpaceWarningTitle=Not Enough Disk Space\nDiskSpaceWarning=Setup requires at least %1 KB of free space to install, but the selected drive only has %2 KB available.%n%nDo you want to continue anyway?\nDirNameTooLong=The folder name or path is too long.\nInvalidDirName=The folder name is not valid.\nBadDirName32=Folder names cannot include any of the following characters:%n%n%1\nDirExistsTitle=Folder Exists\nDirExists=The folder:%n%n%1%n%nalready exists. Would you like to install to that folder anyway?\nDirDoesntExistTitle=Folder Does Not Exist\nDirDoesntExist=The folder:%n%n%1%n%ndoes not exist. Would you like the folder to be created?\n\n; *** \"Select Components\" wizard page\nWizardSelectComponents=Select Components\nSelectComponentsDesc=Which components should be installed?\nSelectComponentsLabel2=Select the components you want to install; clear the components you do not want to install. Click Next when you are ready to continue.\nFullInstallation=Full installation\n; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)\nCompactInstallation=Compact installation\nCustomInstallation=Custom installation\nNoUninstallWarningTitle=Components Exist\nNoUninstallWarning=Setup has detected that the following components are already installed on your computer:%n%n%1%n%nDeselecting these components will not uninstall them.%n%nWould you like to continue anyway?\nComponentSize1=%1 KB\nComponentSize2=%1 MB\nComponentsDiskSpaceGBLabel=Current selection requires at least [gb] GB of disk space.\nComponentsDiskSpaceMBLabel=Current selection requires at least [mb] MB of disk space.\n\n; *** \"Select Additional Tasks\" wizard page\nWizardSelectTasks=Select Additional Tasks\nSelectTasksDesc=Which additional tasks should be performed?\nSelectTasksLabel2=Select the additional tasks you would like Setup to perform while installing [name], then click Next.\n\n; *** \"Select Start Menu Folder\" wizard page\nWizardSelectProgramGroup=Select Start Menu Folder\nSelectStartMenuFolderDesc=Where should Setup place the program's shortcuts?\nSelectStartMenuFolderLabel3=Setup will create the program's shortcuts in the following Start Menu folder.\nSelectStartMenuFolderBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse.\nMustEnterGroupName=You must enter a folder name.\nGroupNameTooLong=The folder name or path is too long.\nInvalidGroupName=The folder name is not valid.\nBadGroupName=The folder name cannot include any of the following characters:%n%n%1\nNoProgramGroupCheck2=&Don't create a Start Menu folder\n\n; *** \"Ready to Install\" wizard page\nWizardReady=Ready to Install\nReadyLabel1=Setup is now ready to begin installing [name] on your computer.\nReadyLabel2a=Click Install to continue with the installation, or click Back if you want to review or change any settings.\nReadyLabel2b=Click Install to continue with the installation.\nReadyMemoUserInfo=User information:\nReadyMemoDir=Destination location:\nReadyMemoType=Setup type:\nReadyMemoComponents=Selected components:\nReadyMemoGroup=Start Menu folder:\nReadyMemoTasks=Additional tasks:\n\n; *** TDownloadWizardPage wizard page and DownloadTemporaryFile\nDownloadingLabel=Downloading additional files...\nButtonStopDownload=&Stop download\nStopDownload=Are you sure you want to stop the download?\nErrorDownloadAborted=Download aborted\nErrorDownloadFailed=Download failed: %1 %2\nErrorDownloadSizeFailed=Getting size failed: %1 %2\nErrorFileHash1=File hash failed: %1\nErrorFileHash2=Invalid file hash: expected %1, found %2\nErrorProgress=Invalid progress: %1 of %2\nErrorFileSize=Invalid file size: expected %1, found %2\n\n; *** \"Preparing to Install\" wizard page\nWizardPreparing=Preparing to Install\nPreparingDesc=Setup is preparing to install [name] on your computer.\nPreviousInstallNotCompleted=The installation/removal of a previous program was not completed. You will need to restart your computer to complete that installation.%n%nAfter restarting your computer, run Setup again to complete the installation of [name].\nCannotContinue=Setup cannot continue. Please click Cancel to exit.\nApplicationsFound=The following applications are using files that need to be updated by Setup. It is recommended that you allow Setup to automatically close these applications.\nApplicationsFound2=The following applications are using files that need to be updated by Setup. It is recommended that you allow Setup to automatically close these applications. After the installation has completed, Setup will attempt to restart the applications.\nCloseApplications=&Automatically close the applications\nDontCloseApplications=&Do not close the applications\nErrorCloseApplications=Setup was unable to automatically close all applications. It is recommended that you close all applications using files that need to be updated by Setup before continuing.\nPrepareToInstallNeedsRestart=Setup must restart your computer. After restarting your computer, run Setup again to complete the installation of [name].%n%nWould you like to restart now?\n\n; *** \"Installing\" wizard page\nWizardInstalling=Installing\nInstallingLabel=Please wait while Setup installs [name] on your computer.\n\n; *** \"Setup Completed\" wizard page\nFinishedHeadingLabel=Completing the [name] Setup Wizard\nFinishedLabelNoIcons=Setup has finished installing [name] on your computer.\nFinishedLabel=Setup has finished installing [name] on your computer. The application may be launched by selecting the installed shortcuts.\nClickFinish=Click Finish to exit Setup.\nFinishedRestartLabel=To complete the installation of [name], Setup must restart your computer. Would you like to restart now?\nFinishedRestartMessage=To complete the installation of [name], Setup must restart your computer.%n%nWould you like to restart now?\nShowReadmeCheck=Yes, I would like to view the README file\nYesRadio=&Yes, restart the computer now\nNoRadio=&No, I will restart the computer later\n; used for example as 'Run MyProg.exe'\nRunEntryExec=Run %1\n; used for example as 'View Readme.txt'\nRunEntryShellExec=View %1\n\n; *** \"Setup Needs the Next Disk\" stuff\nChangeDiskTitle=Setup Needs the Next Disk\nSelectDiskLabel2=Please insert Disk %1 and click OK.%n%nIf the files on this disk can be found in a folder other than the one displayed below, enter the correct path or click Browse.\nPathLabel=&Path:\nFileNotInDir2=The file \"%1\" could not be located in \"%2\". Please insert the correct disk or select another folder.\nSelectDirectoryLabel=Please specify the location of the next disk.\n\n; *** Installation phase messages\nSetupAborted=Setup was not completed.%n%nPlease correct the problem and run Setup again.\nAbortRetryIgnoreSelectAction=Select action\nAbortRetryIgnoreRetry=&Try again\nAbortRetryIgnoreIgnore=&Ignore the error and continue\nAbortRetryIgnoreCancel=Cancel installation\n\n; *** Installation status messages\nStatusClosingApplications=Closing applications...\nStatusCreateDirs=Creating directories...\nStatusExtractFiles=Extracting files...\nStatusCreateIcons=Creating shortcuts...\nStatusCreateIniEntries=Creating INI entries...\nStatusCreateRegistryEntries=Creating registry entries...\nStatusRegisterFiles=Registering files...\nStatusSavingUninstall=Saving uninstall information...\nStatusRunProgram=Finishing installation...\nStatusRestartingApplications=Restarting applications...\nStatusRollback=Rolling back changes...\n\n; *** Misc. errors\nErrorInternal2=Internal error: %1\nErrorFunctionFailedNoCode=%1 failed\nErrorFunctionFailed=%1 failed; code %2\nErrorFunctionFailedWithMessage=%1 failed; code %2.%n%3\nErrorExecutingProgram=Unable to execute file:%n%1\n\n; *** Registry errors\nErrorRegOpenKey=Error opening registry key:%n%1\\%2\nErrorRegCreateKey=Error creating registry key:%n%1\\%2\nErrorRegWriteKey=Error writing to registry key:%n%1\\%2\n\n; *** INI errors\nErrorIniEntry=Error creating INI entry in file \"%1\".\n\n; *** File copying errors\nFileAbortRetryIgnoreSkipNotRecommended=&Skip this file (not recommended)\nFileAbortRetryIgnoreIgnoreNotRecommended=&Ignore the error and continue (not recommended)\nSourceIsCorrupted=The source file is corrupted\nSourceDoesntExist=The source file \"%1\" does not exist\nExistingFileReadOnly2=The existing file could not be replaced because it is marked read-only.\nExistingFileReadOnlyRetry=&Remove the read-only attribute and try again\nExistingFileReadOnlyKeepExisting=&Keep the existing file\nErrorReadingExistingDest=An error occurred while trying to read the existing file:\nFileExistsSelectAction=Select action\nFileExists2=The file already exists.\nFileExistsOverwriteExisting=&Overwrite the existing file\nFileExistsKeepExisting=&Keep the existing file\nFileExistsOverwriteOrKeepAll=&Do this for the next conflicts\nExistingFileNewerSelectAction=Select action\nExistingFileNewer2=The existing file is newer than the one Setup is trying to install.\nExistingFileNewerOverwriteExisting=&Overwrite the existing file\nExistingFileNewerKeepExisting=&Keep the existing file (recommended)\nExistingFileNewerOverwriteOrKeepAll=&Do this for the next conflicts\nErrorChangingAttr=An error occurred while trying to change the attributes of the existing file:\nErrorCreatingTemp=An error occurred while trying to create a file in the destination directory:\nErrorReadingSource=An error occurred while trying to read the source file:\nErrorCopying=An error occurred while trying to copy a file:\nErrorReplacingExistingFile=An error occurred while trying to replace the existing file:\nErrorRestartReplace=RestartReplace failed:\nErrorRenamingTemp=An error occurred while trying to rename a file in the destination directory:\nErrorRegisterServer=Unable to register the DLL/OCX: %1\nErrorRegSvr32Failed=RegSvr32 failed with exit code %1\nErrorRegisterTypeLib=Unable to register the type library: %1\n\n; *** Uninstall display name markings\n; used for example as 'My Program (32-bit)'\nUninstallDisplayNameMark=%1 (%2)\n; used for example as 'My Program (32-bit, All users)'\nUninstallDisplayNameMarks=%1 (%2, %3)\nUninstallDisplayNameMark32Bit=32-bit\nUninstallDisplayNameMark64Bit=64-bit\nUninstallDisplayNameMarkAllUsers=All users\nUninstallDisplayNameMarkCurrentUser=Current user\n\n; *** Post-installation errors\nErrorOpeningReadme=An error occurred while trying to open the README file.\nErrorRestartingComputer=Setup was unable to restart the computer. Please do this manually.\n\n; *** Uninstaller messages\nUninstallNotFound=File \"%1\" does not exist. Cannot uninstall.\nUninstallOpenError=File \"%1\" could not be opened. Cannot uninstall\nUninstallUnsupportedVer=The uninstall log file \"%1\" is in a format not recognized by this version of the uninstaller. Cannot uninstall\nUninstallUnknownEntry=An unknown entry (%1) was encountered in the uninstall log\nConfirmUninstall=Are you sure you want to completely remove %1 and all of its components?\nUninstallOnlyOnWin64=This installation can only be uninstalled on 64-bit Windows.\nOnlyAdminCanUninstall=This installation can only be uninstalled by a user with administrative privileges.\nUninstallStatusLabel=Please wait while %1 is removed from your computer.\nUninstalledAll=%1 was successfully removed from your computer.\nUninstalledMost=%1 uninstall complete.%n%nSome elements could not be removed. These can be removed manually.\nUninstalledAndNeedsRestart=To complete the uninstallation of %1, your computer must be restarted.%n%nWould you like to restart now?\nUninstallDataCorrupted=\"%1\" file is corrupted. Cannot uninstall\n\n; *** Uninstallation phase messages\nConfirmDeleteSharedFileTitle=Remove Shared File?\nConfirmDeleteSharedFile2=The system indicates that the following shared file is no longer in use by any programs. Would you like for Uninstall to remove this shared file?%n%nIf any programs are still using this file and it is removed, those programs may not function properly. If you are unsure, choose No. Leaving the file on your system will not cause any harm.\nSharedFileNameLabel=File name:\nSharedFileLocationLabel=Location:\nWizardUninstalling=Uninstall Status\nStatusUninstalling=Uninstalling %1...\n\n; *** Shutdown block reasons\nShutdownBlockReasonInstallingApp=Installing %1.\nShutdownBlockReasonUninstallingApp=Uninstalling %1.\n\n; The custom messages below aren't used by Setup itself, but if you make\n; use of them in your scripts, you'll want to translate them.\n\n[CustomMessages]\n\nNameAndVersion=%1 version %2\nAdditionalIcons=Additional shortcuts:\nCreateDesktopIcon=Create a &desktop shortcut\nCreateQuickLaunchIcon=Create a &Quick Launch shortcut\nProgramOnTheWeb=%1 on the Web\nUninstallProgram=Uninstall %1\nLaunchProgram=Launch %1\nAssocFileExtension=&Associate %1 with the %2 file extension\nAssocingFileExtension=Associating %1 with the %2 file extension...\nAutoStartProgramGroupDescription=Startup:\nAutoStartProgram=Automatically start %1\nAddonHostProgramNotFound=%1 could not be located in the folder you selected.%n%nDo you want to continue anyway?\n"
  },
  {
    "path": "VirtualSmb/VirtualSmb.cpp",
    "content": "﻿/*\n * PROJECT:    SynthRdp\n * FILE:       VirtualSmb.cpp\n * PURPOSE:    Implementation for Hyper-V Virtual SMB Guest Utility\n *\n * LICENSE:    The MIT License\n *\n * MAINTAINER: MouriNaruto (Kenji.Mouri@outlook.com)\n */\n\n#include <Mile.Internal.h>\n\n#include <cstdio>\n#include <cstring>\n\n// Reference: https://github.com/microsoft/hcsshim\n//            /blob/ed5784127999cfd4c08c254626cc964cb20d7948\n//            /internal/gcs-sidecar/vsmb.go\n\ntypedef struct _SMB2_INSTANCE_CONFIGURATION_17134\n{\n    UINT32 DormantDirectoryTimeout;\n    UINT32 DormantFileTimeout;\n    UINT32 DormantFileLimit;\n    UINT32 FileInfoCacheLifetime;\n    UINT32 FileNotFoundCacheLifetime;\n    UINT32 DirectoryCacheLifetime;\n    UINT32 FileInfoCacheEntriesMax;\n    UINT32 FileNotFoundCacheEntriesMax;\n    UINT32 DirectoryCacheEntriesMax;\n    UINT32 DirectoryCacheSizeMax;\n    UINT8 RequireSecuritySignature;\n    UINT8 RequireEncryption;\n    UINT8 Padding[2];\n} SMB2_INSTANCE_CONFIGURATION_17134, *PSMB2_INSTANCE_CONFIGURATION_17134;\n\ntypedef struct _SMB2_INSTANCE_CONFIGURATION_20348\n{\n    UINT32 DormantDirectoryTimeout;\n    UINT32 DormantFileTimeout;\n    UINT32 DormantFileLimit;\n    UINT32 FileInfoCacheLifetime;\n    UINT32 FileNotFoundCacheLifetime;\n    UINT32 DirectoryCacheLifetime;\n    UINT32 FileInfoCacheEntriesMax;\n    UINT32 FileNotFoundCacheEntriesMax;\n    UINT32 DirectoryCacheEntriesMax;\n    UINT32 DirectoryCacheSizeMax;\n    UINT32 ReadAheadGranularity;\n    UINT8 RequireSecuritySignature;\n    UINT8 RequireEncryption;\n    UINT8 Padding[2];\n} SMB2_INSTANCE_CONFIGURATION_20348, *PSMB2_INSTANCE_CONFIGURATION_20348;\n\ntypedef struct _SMB2_INSTANCE_CONFIGURATION_25398\n{\n    UINT32 DormantDirectoryTimeout;\n    UINT32 DormantFileTimeout;\n    UINT32 DormantFileLimit;\n    UINT32 FileInfoCacheLifetime;\n    UINT32 FileNotFoundCacheLifetime;\n    UINT32 DirectoryCacheLifetime;\n    UINT32 FileInfoCacheEntriesMax;\n    UINT32 FileNotFoundCacheEntriesMax;\n    UINT32 DirectoryCacheEntriesMax;\n    UINT32 DirectoryCacheSizeMax;\n    UINT32 ReadAheadGranularity;\n    UINT32 VolumeFeatureSupportCacheLifetime;\n    UINT32 VolumeFeatureSupportCacheEntriesMax;\n    UINT8 RequireSecuritySignature;\n    UINT8 RequireEncryption;\n    UINT8 Padding[2];\n} SMB2_INSTANCE_CONFIGURATION_25398, *PSMB2_INSTANCE_CONFIGURATION_25398;\n\n// Since 26100.xxxx\ntypedef struct _SMB2_INSTANCE_CONFIGURATION\n{\n    UINT32 DormantDirectoryTimeout;\n    UINT32 DormantFileTimeout;\n    UINT32 DormantFileLimit;\n    UINT32 FileInfoCacheLifetime;\n    UINT32 FileNotFoundCacheLifetime;\n    UINT32 DirectoryCacheLifetime;\n    UINT32 FileInfoCacheEntriesMax;\n    UINT32 FileNotFoundCacheEntriesMax;\n    UINT32 DirectoryCacheEntriesMax;\n    UINT32 DirectoryCacheSizeMax;\n    UINT32 ReadAheadGranularity;\n    UINT32 VolumeFeatureSupportCacheLifetime;\n    UINT32 VolumeFeatureSupportCacheEntriesMax;\n    UINT32 FileAbeStatusCacheLifetime;\n    UINT8 RequireSecuritySignature;\n    UINT8 RequireEncryption;\n    UINT8 Padding[2];\n} SMB2_INSTANCE_CONFIGURATION, *PSMB2_INSTANCE_CONFIGURATION;\n\ntypedef struct _LMR_CONNECTION_PROPERTIES_10586\n{\n    union\n    {\n        UINT8 Value;\n        struct\n        {\n            UINT8 StatusCodeFiltering : 1; // Symbol\n            UINT8 FileInfoCache : 1; // Symbol\n            UINT8 FileNotFoundCache : 1; // Symbol\n            UINT8 DirectoryCache : 1; // Symbol\n            UINT8 Leasing : 1; // Symbol\n            UINT8 SuppressRenames : 1; // Symbol\n            UINT8 ForceMultiChannel : 1; // Symbol\n            UINT8 ForceKeepalive : 1; // Symbol\n        } Fields;\n    } Flags1;\n    union\n    {\n        UINT8 Value;\n        struct\n        {\n            UINT8 DisableBandwidthThrottling : 1; // Symbol\n            UINT8 Reserved : 7;\n        } Fields;\n    } Flags2;\n    UINT8 Padding[2];\n    UINT32 SessionTimeoutInterval;\n    UINT32 CAHandleKeepaliveInterval;\n    UINT32 NonCAHandleKeepaliveInterval;\n    UINT32 ActiveIOKeepaliveInterval;\n} LMR_CONNECTION_PROPERTIES_10586, *PLMR_CONNECTION_PROPERTIES_10586;\n\ntypedef struct _LMR_CONNECTION_PROPERTIES_25398\n{\n    union\n    {\n        UINT8 Value;\n        struct\n        {\n            UINT8 StatusCodeFiltering : 1; // Symbol\n            UINT8 FileInfoCache : 1; // Symbol\n            UINT8 FileNotFoundCache : 1; // Symbol\n            UINT8 DirectoryCache : 1; // Symbol\n            UINT8 Leasing : 1; // Symbol\n            UINT8 SuppressRenames : 1; // Symbol\n            UINT8 ForceMultiChannel : 1; // Symbol\n            UINT8 ForceKeepalive : 1; // Symbol\n        } Fields;\n    } Flags1;\n    union\n    {\n        UINT8 Value;\n        struct\n        {\n            UINT8 DisableBandwidthThrottling : 1; // Symbol\n            UINT8 Reserved : 7;\n        } Fields;\n    } Flags2;\n    UINT8 Padding[2];\n    UINT32 SessionTimeoutInterval;\n    UINT32 CAHandleKeepaliveInterval;\n    UINT32 NonCAHandleKeepaliveInterval;\n    UINT32 ActiveIOKeepaliveInterval;\n    UINT32 DisableRdma;\n    UINT32 ConnectionCountPerRdmaInterface;\n} LMR_CONNECTION_PROPERTIES_25398, *PLMR_CONNECTION_PROPERTIES_25398;\n\n// Since 26100.1\ntypedef struct _LMR_CONNECTION_PROPERTIES\n{\n    union\n    {\n        UINT8 Value;\n        struct\n        {\n            UINT8 StatusCodeFiltering : 1; // Symbol\n            UINT8 FileInfoCache : 1; // Symbol\n            UINT8 FileNotFoundCache : 1; // Symbol\n            UINT8 DirectoryCache : 1; // Symbol\n            UINT8 Leasing : 1; // Symbol\n            UINT8 SuppressRenames : 1; // Symbol\n            UINT8 ForceMultiChannel : 1; // Symbol\n            UINT8 ForceKeepalive : 1; // Symbol\n        } Fields;\n    } Flags1;\n    union\n    {\n        UINT8 Value;\n        struct\n        {\n            UINT8 DisableBandwidthThrottling : 1; // Symbol\n            UINT8 Reserved : 7;\n        } Fields;\n    } Flags2;\n    UINT8 Padding[2];\n    UINT32 SessionTimeoutInterval;\n    UINT32 CAHandleKeepaliveInterval;\n    UINT32 NonCAHandleKeepaliveInterval;\n    UINT32 ActiveIOKeepaliveInterval;\n    UINT32 DisableRdma;\n    UINT32 ConnectionCountPerRdmaInterface;\n    UINT16 AlternateTCPPort;\n    UINT16 AlternateQuicPort;\n    UINT16 AlternateRdmaPort;\n    UINT8 Padding2[2];\n} LMR_CONNECTION_PROPERTIES, *PLMR_CONNECTION_PROPERTIES;\n\n#define LMR_INSTANCE_FLAG_REGISTER_FILESYSTEM 0x2\n#define LMR_INSTANCE_FLAG_USE_CUSTOM_TRANSPORTS 0x4\n#define LMR_INSTANCE_FLAG_ALLOW_GUEST_AUTH 0x8\n#define LMR_INSTANCE_FLAG_SUPPORTS_DIRECTMAPPED_IO 0x10\n\ntypedef struct _LMR_START_INSTANCE_REQUEST_10586\n{\n    UINT32 StructureSize;\n    UINT32 IoTimeout;\n    UINT32 IoRetryCount;\n    UINT16 Flags; // LMR_INSTANCE_FLAG_*\n    UINT16 AlternatePort; // Symbol\n    UINT32 Reserved1;\n    LMR_CONNECTION_PROPERTIES_10586 DefaultConnectionProperties;\n    UINT8 InstanceId;\n    UINT8 Reserved2;\n    UINT16 DeviceNameLength;\n    WCHAR DeviceName[ANYSIZE_ARRAY]; // Symbol\n} LMR_START_INSTANCE_REQUEST_10586, *PLMR_START_INSTANCE_REQUEST_10586;\n\ntypedef struct _LMR_START_INSTANCE_REQUEST_17134\n{\n    UINT32 StructureSize;\n    UINT32 IoTimeout;\n    UINT32 IoRetryCount;\n    UINT16 Flags; // LMR_INSTANCE_FLAG_*\n    UINT16 AlternatePort; // Symbol\n    UINT32 Reserved1;\n    SMB2_INSTANCE_CONFIGURATION_17134 InstanceConfig;\n    LMR_CONNECTION_PROPERTIES_10586 DefaultConnectionProperties;\n    UINT8 InstanceId;\n    UINT8 Reserved2;\n    UINT16 DeviceNameLength;\n    WCHAR DeviceName[ANYSIZE_ARRAY]; // Symbol\n} LMR_START_INSTANCE_REQUEST_17134, *PLMR_START_INSTANCE_REQUEST_17134;\n\ntypedef struct _LMR_START_INSTANCE_REQUEST_20348\n{\n    UINT32 StructureSize;\n    UINT32 IoTimeout;\n    UINT32 IoRetryCount;\n    UINT16 Flags; // LMR_INSTANCE_FLAG_*\n    UINT16 AlternatePort; // Symbol\n    UINT32 Reserved1;\n    SMB2_INSTANCE_CONFIGURATION_20348 InstanceConfig;\n    LMR_CONNECTION_PROPERTIES_10586 DefaultConnectionProperties;\n    UINT8 InstanceId;\n    UINT8 Reserved2;\n    UINT16 DeviceNameLength;\n    WCHAR DeviceName[ANYSIZE_ARRAY]; // Symbol\n} LMR_START_INSTANCE_REQUEST_20348, *PLMR_START_INSTANCE_REQUEST_20348;\n\ntypedef struct _LMR_START_INSTANCE_REQUEST_25398\n{\n    UINT32 StructureSize;\n    UINT32 IoTimeout;\n    UINT32 IoRetryCount;\n    UINT16 Flags; // LMR_INSTANCE_FLAG_*\n    UINT16 AlternatePort; // Symbol\n    UINT32 Reserved1;\n    SMB2_INSTANCE_CONFIGURATION_25398 InstanceConfig;\n    LMR_CONNECTION_PROPERTIES_25398 DefaultConnectionProperties;\n    UINT8 InstanceId;\n    UINT8 Reserved2;\n    UINT16 DeviceNameLength;\n    WCHAR DeviceName[ANYSIZE_ARRAY]; // Symbol\n} LMR_START_INSTANCE_REQUEST_25398, *PLMR_START_INSTANCE_REQUEST_25398;\n\ntypedef struct _LMR_START_INSTANCE_REQUEST_26100\n{\n    UINT32 StructureSize;\n    UINT32 IoTimeout;\n    UINT32 IoRetryCount;\n    UINT16 Flags; // LMR_INSTANCE_FLAG_*\n    UINT16 AlternatePort; // Symbol\n    UINT32 Reserved1;\n    SMB2_INSTANCE_CONFIGURATION_25398 InstanceConfig;\n    LMR_CONNECTION_PROPERTIES DefaultConnectionProperties;\n    UINT8 InstanceId;\n    UINT8 Reserved2;\n    UINT16 DeviceNameLength;\n    WCHAR DeviceName[ANYSIZE_ARRAY]; // Symbol\n} LMR_START_INSTANCE_REQUEST_26100, *PLMR_START_INSTANCE_REQUEST_26100;\n\ntypedef struct _LMR_START_INSTANCE_REQUEST\n{\n    UINT32 StructureSize;\n    UINT32 IoTimeout;\n    UINT32 IoRetryCount;\n    UINT16 Flags; // LMR_INSTANCE_FLAG_*\n    UINT16 AlternatePort; // Symbol\n    UINT32 Reserved1;\n    SMB2_INSTANCE_CONFIGURATION InstanceConfig;\n    LMR_CONNECTION_PROPERTIES DefaultConnectionProperties;\n    UINT8 InstanceId;\n    UINT8 Reserved2;\n    UINT16 DeviceNameLength;\n    WCHAR DeviceName[ANYSIZE_ARRAY]; // Symbol\n} LMR_START_INSTANCE_REQUEST, *PLMR_START_INSTANCE_REQUEST;\n\n#ifndef FSCTL_LMR_START_INSTANCE\n#define FSCTL_LMR_START_INSTANCE CTL_CODE( \\\n    FILE_DEVICE_NETWORK_FILE_SYSTEM, \\\n    232, \\\n    METHOD_BUFFERED, \\\n    FILE_ANY_ACCESS)\n#endif // !FSCTL_LMR_START_INSTANCE\n\ntypedef enum _LMR_TRANSPORT_TYPE\n{\n    SmbCeTransportTypeTdi = 0x0,\n    SmbCeTransportTypeTcpIp = 0x1,\n    SmbCeTransportTypeVmbus = 0x2,\n} LMR_TRANSPORT_TYPE, *PLMR_TRANSPORT_TYPE;\n\ntypedef struct _LMR_BIND_UNBIND_TRANSPORT_REQUEST\n{\n    UINT16 StructureSize;\n    UINT16 Flags;\n    LMR_TRANSPORT_TYPE Type;\n    UINT TransportIdLength;\n    WCHAR TransportId[ANYSIZE_ARRAY];\n} LMR_BIND_UNBIND_TRANSPORT_REQUEST, *PLMR_BIND_UNBIND_TRANSPORT_REQUEST;\n\n#ifndef FSCTL_LMR_BIND_TO_TRANSPORT\n#define FSCTL_LMR_BIND_TO_TRANSPORT CTL_CODE( \\\n    FILE_DEVICE_NETWORK_FILE_SYSTEM, \\\n    108, \\\n    METHOD_BUFFERED, \\\n    FILE_ANY_ACCESS)\n#endif // !FSCTL_LMR_BIND_TO_TRANSPORT\n\ntemplate <typename RequestType>\nNTSTATUS LanmanRedirectorStartInstance(\n    _In_ HANDLE Handle)\n{\n    const WCHAR DeviceName[] = L\"\\\\Device\\\\vmsmb\";\n    const std::size_t DeviceNameLength =\n        (sizeof(DeviceName) / sizeof(WCHAR)) - 1;\n\n    const std::size_t RequestBufferSize =\n        FIELD_OFFSET(RequestType, DeviceName) +\n        sizeof(WCHAR) * DeviceNameLength;\n    UINT8 RequestBuffer[RequestBufferSize] = {};\n\n    RequestType* Request = reinterpret_cast<RequestType*>(RequestBuffer);\n    Request->StructureSize =\n        FIELD_OFFSET(LMR_START_INSTANCE_REQUEST, DeviceName);\n    Request->IoTimeout = 30;\n    Request->IoRetryCount = 3;\n    Request->Flags =\n        LMR_INSTANCE_FLAG_REGISTER_FILESYSTEM |\n        LMR_INSTANCE_FLAG_USE_CUSTOM_TRANSPORTS |\n        LMR_INSTANCE_FLAG_ALLOW_GUEST_AUTH |\n        LMR_INSTANCE_FLAG_SUPPORTS_DIRECTMAPPED_IO;\n    Request->Reserved1 = 0;\n    Request->DefaultConnectionProperties.Flags1.Value = 0x1F;\n    Request->DefaultConnectionProperties.SessionTimeoutInterval = 55;\n    Request->DefaultConnectionProperties.CAHandleKeepaliveInterval = 10;\n    Request->DefaultConnectionProperties.NonCAHandleKeepaliveInterval = 30;\n    Request->DefaultConnectionProperties.ActiveIOKeepaliveInterval = 30;\n    Request->InstanceId = 1;\n    Request->DeviceNameLength = DeviceNameLength * sizeof(WCHAR);\n    std::memcpy(\n        Request->DeviceName,\n        DeviceName,\n        sizeof(DeviceName) - sizeof(WCHAR));\n    IO_STATUS_BLOCK IoStatusBlock = {};\n    return ::NtFsControlFile(\n        Handle,\n        nullptr,\n        nullptr,\n        nullptr,\n        &IoStatusBlock,\n        FSCTL_LMR_START_INSTANCE,\n        RequestBuffer,\n        RequestBufferSize,\n        nullptr,\n        0);\n}\n\nint main()\n{\n    NTSTATUS Status = STATUS_SUCCESS;\n\n    HANDLE LanmanRedirectorHandle = INVALID_HANDLE_VALUE;\n    {\n        UNICODE_STRING LanmanRedirectorDevicePath = RTL_CONSTANT_STRING(\n            L\"\\\\Device\\\\LanmanRedirector\");\n        OBJECT_ATTRIBUTES ObjectAttributes = {};\n        ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);\n        ObjectAttributes.ObjectName = &LanmanRedirectorDevicePath;\n        ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE;\n        IO_STATUS_BLOCK IoStatusBlock = {};\n        Status = ::NtCreateFile(\n            &LanmanRedirectorHandle,\n            FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,\n            &ObjectAttributes,\n            &IoStatusBlock,\n            0,\n            0,\n            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            0,\n            nullptr,\n            0);\n    }\n    if (NT_SUCCESS(Status))\n    {\n        do\n        {\n            // 120: 26100.xxxx 28000\n            {\n                using RequestType = LMR_START_INSTANCE_REQUEST;\n                Status = ::LanmanRedirectorStartInstance<RequestType>(\n                    LanmanRedirectorHandle);\n                if (NT_SUCCESS(Status) ||\n                    STATUS_OBJECT_NAME_COLLISION == Status)\n                {\n                    break;\n                }\n                std::printf(\n                    \"%s with %s failed: 0x%08X, trying to fallback...\\n\",\n                    \"LanmanRedirectorStartInstance\",\n                    \"LMR_START_INSTANCE_REQUEST\",\n                    Status);\n            }\n\n            // 116: 26100\n            {\n                using RequestType = LMR_START_INSTANCE_REQUEST_26100;\n                Status = ::LanmanRedirectorStartInstance<RequestType>(\n                    LanmanRedirectorHandle);\n                if (NT_SUCCESS(Status) ||\n                    STATUS_OBJECT_NAME_COLLISION == Status)\n                {\n                    break;\n                }\n                std::printf(\n                    \"%s with %s failed: 0x%08X, trying to fallback...\\n\",\n                    \"LanmanRedirectorStartInstance\",\n                    \"LMR_START_INSTANCE_REQUEST_26100\",\n                    Status);\n            }\n\n            // 108: 25398\n            {\n                using RequestType = LMR_START_INSTANCE_REQUEST_25398;\n                Status = ::LanmanRedirectorStartInstance<RequestType>(\n                    LanmanRedirectorHandle);\n                if (NT_SUCCESS(Status) ||\n                    STATUS_OBJECT_NAME_COLLISION == Status)\n                {\n                    break;\n                }\n                std::printf(\n                    \"%s with %s failed: 0x%08X, trying to fallback...\\n\",\n                    \"LanmanRedirectorStartInstance\",\n                    \"LMR_START_INSTANCE_REQUEST_25398\",\n                    Status);\n            }\n\n            // 92: 20348 22000 22621\n            {\n                using RequestType = LMR_START_INSTANCE_REQUEST_20348;\n                Status = ::LanmanRedirectorStartInstance<RequestType>(\n                    LanmanRedirectorHandle);\n                if (NT_SUCCESS(Status) ||\n                    STATUS_OBJECT_NAME_COLLISION == Status)\n                {\n                    break;\n                }\n                std::printf(\n                    \"%s with %s failed: 0x%08X, trying to fallback...\\n\",\n                    \"LanmanRedirectorStartInstance\",\n                    \"LMR_START_INSTANCE_REQUEST_20348\",\n                    Status);\n            }\n\n            // 88: 17134 17763 18362 19041\n            {\n                using RequestType = LMR_START_INSTANCE_REQUEST_17134;\n                Status = ::LanmanRedirectorStartInstance<RequestType>(\n                    LanmanRedirectorHandle);\n                if (NT_SUCCESS(Status) ||\n                    STATUS_OBJECT_NAME_COLLISION == Status)\n                {\n                    break;\n                }\n                std::printf(\n                    \"%s with %s failed: 0x%08X, trying to fallback...\\n\",\n                    \"LanmanRedirectorStartInstance\",\n                    \"LMR_START_INSTANCE_REQUEST_17134\",\n                    Status);\n            }\n\n            // 44: 10586 14393 15063 16299\n            {\n                using RequestType = LMR_START_INSTANCE_REQUEST_10586;\n                Status = ::LanmanRedirectorStartInstance<RequestType>(\n                    LanmanRedirectorHandle);\n                if (NT_SUCCESS(Status) ||\n                    STATUS_OBJECT_NAME_COLLISION == Status)\n                {\n                    break;\n                }\n                std::printf(\n                    \"%s with %s failed: 0x%08X, trying to fallback...\\n\",\n                    \"LanmanRedirectorStartInstance\",\n                    \"LMR_START_INSTANCE_REQUEST_10586\",\n                    Status);\n            }\n\n            // 0: 10240 and earlier\n            {\n                Status = STATUS_NOT_SUPPORTED;\n            }\n\n        } while (false);\n\n        if (NT_SUCCESS(Status))\n        {\n            std::printf(\"SMB redirector instance started successfully.\\n\");\n        }\n        else if (STATUS_OBJECT_NAME_COLLISION == Status)\n        {\n            std::printf(\n                \"SMB redirector instance already started.\\n\");\n        }\n        else\n        {\n            std::printf(\n                \"LanmanRedirectorStartInstance failed with all known request \"\n                \"structures, cannot start SMB redirector instance.\");\n        }\n\n        ::CloseHandle(LanmanRedirectorHandle);\n    }\n\n    HANDLE VmSmbHandle = INVALID_HANDLE_VALUE;\n    {\n        UNICODE_STRING VmSmbDevicePath = RTL_CONSTANT_STRING(\n            L\"\\\\Device\\\\vmsmb\");\n        OBJECT_ATTRIBUTES ObjectAttributes = {};\n        ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);\n        ObjectAttributes.ObjectName = &VmSmbDevicePath;\n        ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE;\n        IO_STATUS_BLOCK IoStatusBlock = {};\n        Status = ::NtCreateFile(\n            &VmSmbHandle,\n            FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,\n            &ObjectAttributes,\n            &IoStatusBlock,\n            0,\n            0,\n            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n            FILE_OPEN,\n            0,\n            nullptr,\n            0);\n    }\n    if (NT_SUCCESS(Status))\n    {\n        const WCHAR DeviceName[] =\n            L\"\\\\Device\\\\VMBus\\\\{4d12e519-17a0-4ae4-8eaa-5270fc6abdb7}-{dcc079ae-60ba-4d07-847c-3493609c0870}-0000\";\n        const std::size_t DeviceNameLength =\n            (sizeof(DeviceName) / sizeof(WCHAR)) - 1;\n\n        const std::size_t RequestBufferSize =\n            FIELD_OFFSET(LMR_BIND_UNBIND_TRANSPORT_REQUEST, TransportId) +\n            sizeof(WCHAR) * DeviceNameLength;\n        UINT8 RequestBuffer[RequestBufferSize] = {};\n\n        PLMR_BIND_UNBIND_TRANSPORT_REQUEST Request =\n            reinterpret_cast<PLMR_BIND_UNBIND_TRANSPORT_REQUEST>(RequestBuffer);\n        Request->StructureSize = sizeof(LMR_BIND_UNBIND_TRANSPORT_REQUEST);\n        Request->Flags = 0;\n        Request->Type = SmbCeTransportTypeVmbus;\n        Request->TransportIdLength = DeviceNameLength * sizeof(WCHAR);\n        std::memcpy(\n            Request->TransportId,\n            DeviceName,\n            sizeof(DeviceName) - sizeof(WCHAR));\n        IO_STATUS_BLOCK IoStatusBlock = {};\n        Status = ::NtFsControlFile(\n            VmSmbHandle,\n            nullptr,\n            nullptr,\n            nullptr,\n            &IoStatusBlock,\n            FSCTL_LMR_BIND_TO_TRANSPORT,\n            RequestBuffer,\n            RequestBufferSize,\n            nullptr,\n            0);\n        if (NT_SUCCESS(Status))\n        {\n            std::printf(\"VMBUS transport bound to SMB redirector instance.\\n\");\n        }\n        else\n        {\n            std::printf(\n                \"Failed to bind VMBUS transport to SMB redirector instance: \"\n                \"0x%08X\\n\",\n                Status);\n        }\n    }\n\n    {\n        HANDLE Handle = INVALID_HANDLE_VALUE;\n        {\n            UNICODE_STRING VmSmbDevicePath = RTL_CONSTANT_STRING(\n                L\"\\\\Device\\\\vmsmb\\\\VSMB-{dcc079ae-60ba-4d07-847c-3493609c0870}\\\\NanaBox.HostDrivers\");\n            OBJECT_ATTRIBUTES ObjectAttributes = {};\n            ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);\n            ObjectAttributes.ObjectName = &VmSmbDevicePath;\n            ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE;\n            IO_STATUS_BLOCK IoStatusBlock = {};\n            Status = ::NtCreateFile(\n                &Handle,\n                FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,\n                &ObjectAttributes,\n                &IoStatusBlock,\n                0,\n                0,\n                FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,\n                FILE_OPEN,\n                0,\n                nullptr,\n                0);\n        }\n    }\n\n    std::getchar();\n\n    return 0;\n}\n"
  },
  {
    "path": "VirtualSmb/VirtualSmb.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n\t<compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n\t\t<application>\n\t\t\t<supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>\n\t\t</application>\n\t</compatibility>\n</assembly>\n"
  },
  {
    "path": "VirtualSmb/VirtualSmb.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{0A6FBD98-1210-4B36-A031-3E2D57E89DE3}</ProjectGuid>\n    <RootNamespace>VirtualSmb</RootNamespace>\n    <MileProjectType>ConsoleApplication</MileProjectType>\n    <MileProjectManifestFile>VirtualSmb.manifest</MileProjectManifestFile>\n    <MileProjectUseProjectProperties>true</MileProjectUseProjectProperties>\n    <MileProjectCompanyName>Project Mile</MileProjectCompanyName>\n    <MileProjectFileDescription>Hyper-V Virtual SMB Guest Utility</MileProjectFileDescription>\n    <MileProjectInternalName>VirtualSmb</MileProjectInternalName>\n    <MileProjectLegalCopyright>© M2-Team and Contributors. All rights reserved.</MileProjectLegalCopyright>\n    <MileProjectOriginalFilename>VirtualSmb.exe</MileProjectOriginalFilename>\n    <MileProjectProductName>NanaRun</MileProjectProductName>\n    <MileProjectVersion>1.0.$([System.DateTime]::Today.Subtract($([System.DateTime]::Parse('2024-05-01'))).TotalDays).0</MileProjectVersion>\n    <MileProjectVersionTag>Preview 3</MileProjectVersionTag>\n    <MileUniCrtDisableRuntimeDebuggingFeature>true</MileUniCrtDisableRuntimeDebuggingFeature>\n    <MileUniCrtEnableVcRuntimeWrapper>false</MileUniCrtEnableVcRuntimeWrapper>\n    <MileWindowsHelpersNoCppWinRTHelpers>true</MileWindowsHelpersNoCppWinRTHelpers>\n  </PropertyGroup>\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Platform.x86.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Platform.x64.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Platform.ARM64.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Cpp.Default.props\" />\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Cpp.props\" />\n  <Import Project=\"..\\NanaRun.IconResource\\NanaRun.IconResource.props\" />\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <RuntimeLibrary Condition=\"'$(Configuration)' == 'Debug'\">MultiThreadedDebug</RuntimeLibrary>\n      <RuntimeLibrary Condition=\"'$(Configuration)' == 'Release'\">MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"VirtualSmb.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Manifest Include=\"VirtualSmb.manifest\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Mile.Windows.UniCrt\">\n      <Version>1.2.410</Version>\n    </PackageReference>\n    <PackageReference Include=\"Mile.Windows.Internal\">\n      <Version>1.0.3550</Version>\n    </PackageReference>\n    <PackageReference Include=\"Mile.Windows.Helpers\">\n      <Version>1.0.1171</Version>\n    </PackageReference>\n  </ItemGroup>\n  <Import Sdk=\"Mile.Project.Configurations\" Version=\"1.0.1917\" Project=\"Mile.Project.Cpp.targets\" />\n</Project>"
  }
]