栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

将Windows Terminal 添加到右键菜单,使用 Scoop 安装

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

将Windows Terminal 添加到右键菜单,使用 Scoop 安装

概览
  • 注意事项
  • Windows Terminal 安装
  • PowerShell 安装
  • sudo 安装
  • 构建 `install.ps1` 文件并执行
  • 确认已经成功添加到右键菜单:
  • `install.ps1` 具体代码

注意事项

本文只针对使用 Scoop 安装 Windows Terminal 的情况,如果你通过应用商店安装,可以参考:

  • 博客 将 Windows Terminal 添加到 Windows 右键菜单(管理员方式、可选配置)
  • 知乎问题 新发布的Windows Terminal如何添加到右键菜单?

本文默认读者掌握基本的 Scoop 使用方法,不会详细讲解 Scoop 相关命令


本文撰写时间:2022年5月12日
环境:Windows 10 版本 21H1(内部版本 19043.1706)
Scoop版本:0.2.0
Windows Terminal版本:1.12.10982.0
PowerShell 版本:7.2.2


Windows Terminal 安装
scoop install windows-terminal

需要提前添加 extras bucket

PowerShell 安装

必须保证 PowerShell 版本不低于 7.0

scoop install powershell

需要提前添加 dorado bucket

sudo 安装

因为需要用管理员权限执行文件,故下载 sudo
顾名思义,这和 Linux 下的 sudo 命令是一个作用,获取管理员权限

scoop install sudo

需要提前添加 main bucket

构建 install.ps1 文件并执行

在桌面(或其他目录下)新建一个 install.ps1 文件(为了版面舒适,该文件内容在本文末尾处,读者可自行前往复制)

切换到桌面(或其他目录下)使用 sudo 执行该文件

确认已经成功添加到右键菜单:

install.ps1 具体代码

代码来源: windowsterminal-shell-scoop/install.ps1

#Requires -RunAsAdministrator
#Requires -Version 6

[CmdletBinding()]
param(
    [Parameter(Position = 0)]
    [ValidateSet('Default', 'Flat', 'Mini')]
    [string] $Layout = 'Default',
    [Parameter()]
    [switch] $PreRelease
)

function Generate-HelperScript(
        # The cache folder
        [Parameter(Mandatory=$true)]
        [string]$cache)
{
    $content = 
    "Set shell = WScript.CreateObject(`"Shell.Application`")
     executable = WSCript.Arguments(0)
     folder = WScript.Arguments(1)
     If Wscript.Arguments.Count > 2 Then
         profile = WScript.Arguments(2)
         ' 0 at the end means to run this command silently
         shell.ShellExecute `"powershell`", `"Start-Process `"`"`" & executable & `"`"`" -ArgumentList `"`"-p `"`"`"`"`" & profile & `"`"`"`"`" -d `"`"`"`"`" & folder & `"`"`"`"`" `"`" `", `"`", `"runas`", 0
     Else
         ' 0 at the end means to run this command silently
         shell.ShellExecute `"powershell`", `"Start-Process `"`"`" & executable & `"`"`" -ArgumentList `"`"-d `"`"`"`"`" & folder & `"`"`"`"`" `"`" `", `"`", `"runas`", 0
     End If
    "
    Set-Content -Path "$cache/helper.vbs" -Value $content
}

# https://github.com/Duffney/PowerShell/blob/master/FileSystems/Get-Icon.ps1

Function Get-Icon {

    [CmdletBinding()]
    
    Param ( 
        [Parameter(Mandatory=$True, Position=1, HelpMessage="Enter the location of the .EXE file")]
        [string]$File,

        # If provided, will output the icon to a location
        [Parameter(Position=1, ValueFromPipelineByPropertyName=$true)]
        [string]$OutputFile
    )
    
    [System.Reflection.Assembly]::LoadWithPartialName('System.Drawing')  | Out-Null
    
    [System.Drawing.Icon]::ExtractAssociatedIcon($File).ToBitmap().Save($OutputFile)
}

# https://gist.github.com/darkfall/1656050
function ConvertTo-Icon
{
    <#
    .Synopsis
        Converts image to icons
    .Description
        Converts an image to an icon
    .Example
        ConvertTo-Icon -File .Logo.png -OutputFile .Favicon.ico
    #>
    [CmdletBinding()]
    param(
    # The file
    [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
    [Alias('Fullname')]
    [string]$File,
   
    # If provided, will output the icon to a location
    [Parameter(Position=1, ValueFromPipelineByPropertyName=$true)]
    [string]$OutputFile
    )
    
    begin {
        Add-Type -AssemblyName System.Drawing   
    }
    
    process {
        #region Load Icon
        $resolvedFile = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($file)
        if (-not $resolvedFile) { return }
        $inputBitmap = [Drawing.Image]::FromFile($resolvedFile)
        $width = $inputBitmap.Width
        $height = $inputBitmap.Height
        $size = New-Object Drawing.Size $width, $height
        $newBitmap = New-Object Drawing.Bitmap $inputBitmap, $size
        #endregion Load Icon

        #region Icon Size bound check
        if ($width -gt 255 -or $height -gt 255) {
            $ratio = ($height, $width | Measure-Object -Maximum).Maximum / 255
            $width /= $ratio
            $height /= $ratio
        }
        #endregion Icon Size bound check

        #region Save Icon                     
        $memoryStream = New-Object System.IO.MemoryStream
        $newBitmap.Save($memoryStream, [System.Drawing.Imaging.ImageFormat]::Png)

        $resolvedOutputFile = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($outputFile)
        $output = [IO.File]::Create("$resolvedOutputFile")
        
        $iconWriter = New-Object System.IO.BinaryWriter($output)
        # 0-1 reserved, 0
        $iconWriter.Write([byte]0)
        $iconWriter.Write([byte]0)

        # 2-3 image type, 1 = icon, 2 = cursor
        $iconWriter.Write([short]1);

        # 4-5 number of images
        $iconWriter.Write([short]1);

        # image entry 1
        # 0 image width
        $iconWriter.Write([byte]$width);
        # 1 image height
        $iconWriter.Write([byte]$height);

        # 2 number of colors
        $iconWriter.Write([byte]0);

        # 3 reserved
        $iconWriter.Write([byte]0);

        # 4-5 color planes
        $iconWriter.Write([short]0);

        # 6-7 bits per pixel
        $iconWriter.Write([short]32);

        # 8-11 size of image data
        $iconWriter.Write([int]$memoryStream.Length);

        # 12-15 offset of image data
        $iconWriter.Write([int](6 + 16));

        # write image data
        # png data must contain the whole png data file
        $iconWriter.Write($memoryStream.ToArray());

        $iconWriter.Flush();
        $output.Close()               
        #endregion Save Icon

        #region Cleanup
        $memoryStream.Dispose()
        $newBitmap.Dispose()
        $inputBitmap.Dispose()
        #endregion Cleanup
    }
}

function GetProgramFilesFolder(
    [Parameter(Mandatory=$true)]
    [bool]$includePreview)
{
    if (Test-Path "$env:USERPROFILEscoopappswindows-terminal") {
        $result = "$env:USERPROFILEscoopappswindows-terminalcurrent"
        return $result
    } else {
        $root = "$Env:ProgramFilesWindowsApps"
    }
    $versionFolders = (Get-ChildItem $root | Where-Object {
            if ($includePreview) {
                $_.Name -like "Microsoft.WindowsTerminal_*__*" -or
                $_.Name -like "Microsoft.WindowsTerminalPreview_*__*"
            } else {
                $_.Name -like "Microsoft.WindowsTerminal_*__*"
            }
        })
    $foundVersion = $null
    $result = $null
    foreach ($versionFolder in $versionFolders) {
        if ($versionFolder.Name -match "[0-9]+.[0-9]+.[0-9]+.[0-9]+") {
            $version = [version]$Matches.0
            Write-Host "Found Windows Terminal version $version."
            if ($null -eq $foundVersion -or $version -gt $foundVersion) {
                $foundVersion = $version
                $result = $versionFolder.FullName
            }
        } else {
            Write-Warning "Found Windows Terminal unsupported version in $versionFolder."
        }
    }

    if ($null -eq $result) {
        Write-Error "Failed to find Windows Terminal actual folder under $root. To install menu items for Windows Terminal Preview, run with ""-Prerelease"" switch Exit."
        exit 1
    }

    if ($foundVersion -lt [version]"0.11") {
        Write-Warning "The latest version found is less than 0.11, which is not tested. The install script might fail in certain way."
    }

    return $result
}

function GetWindowsTerminalIcon(
    [Parameter(Mandatory=$true)]
    [string]$folder,
    [Parameter(Mandatory=$true)]
    [string]$localCache)
{
    $icon = "$localCachewt.ico"
    $actual = $folder + "WindowsTerminal.exe"
    if (Test-Path $actual) {
        # use app icon directly.
        Write-Host "Found actual executable $actual."
        $temp = "$localCachewt.png"
        Get-Icon -File $actual -OutputFile $temp
        ConvertTo-Icon -File $temp -OutputFile $icon
    } else {
        # download from GitHub
        Write-Warning "Didn't find actual executable $actual so download icon from GitHub."
        Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/microsoft/terminal/master/res/terminal.ico" -OutFile $icon
    }

    return $icon
}

function GetActiveProfiles(
    [Parameter(Mandatory=$true)]
    [bool]$isPreview,
    [bool]$isScoop)
{
    if ($isScoop) {
        $file = "$env:LocalAppDataMicrosoftWindows Terminalsettings.json"
    }
    elseif ($isPreview) {
        $file = "$env:LocalAppDataPackagesMicrosoft.WindowsTerminalPreview_8wekyb3d8bbweLocalStatesettings.json"
    } else {
        $file = "$env:LocalAppDataPackagesMicrosoft.WindowsTerminal_8wekyb3d8bbweLocalStatesettings.json"
    }
    if (-not (Test-Path $file)) {
        Write-Error "Couldn't find profiles. Please run Windows Terminal at least once after installing it. Exit."
        exit 1
    }

    $settings = Get-Content $file | Out-String | ConvertFrom-Json
    if ($settings.profiles.PSObject.Properties.name -match "list") {
        $list = $settings.profiles.list
    } else {
        $list = $settings.profiles 
    }

    return $list | Where-Object { -not $_.hidden} | Where-Object { ($null -eq $_.source) -or -not ($settings.disabledProfileSources -contains $_.source) }
}

function GetProfileIcon (
    [Parameter(Mandatory=$true)]
    $profile,
    [Parameter(Mandatory=$true)]
    [string]$folder,
    [Parameter(Mandatory=$true)]
    [string]$localCache,
    [Parameter(Mandatory=$true)]
    [string]$defaultIcon,
    [Parameter(Mandatory=$true)]
    [bool]$isPreview,
    [bool]$isScoop)
{
    $guid = $profile.guid
    $name = $profile.name
    $result = $null
    $profilePng = $null
    $icon = $profile.icon
    if ($null -ne $icon) {
        if (Test-Path $icon) {
            # use user setting
            $profilePng = $icon  
        } elseif ($profile.icon -like "ms-appdata:///Roaming/*") {
            #resolve roaming cache
            if ($isPreview) {
                $profilePng = $icon -replace "ms-appdata:///Roaming", "$Env:LOCALAPPDATAPackagesMicrosoft.WindowsTerminalPreview_8wekyb3d8bbweRoamingState" -replace "/", ""
            } else {
                $profilePng = $icon -replace "ms-appdata:///Roaming", "$Env:LOCALAPPDATAPackagesMicrosoft.WindowsTerminal_8wekyb3d8bbweRoamingState" -replace "/", ""
            }
        } elseif ($profile.icon -like "ms-appdata:///Local/*") {
            #resolve local cache
            if ($isPreview) {
                $profilePng = $icon -replace "ms-appdata:///Local", "$Env:LOCALAPPDATAPackagesMicrosoft.WindowsTerminalPreview_8wekyb3d8bbweLocalState" -replace "/", ""
            } else {
                $profilePng = $icon -replace "ms-appdata:///Local", "$Env:LOCALAPPDATAPackagesMicrosoft.WindowsTerminal_8wekyb3d8bbweLocalState" -replace "/", ""
            }
        } elseif ($profile.icon -like "ms-appx:///*") {
            # resolve app cache
            $profilePng = $icon -replace "ms-appx://", $folder -replace "/", ""
        } elseif ($profile.icon -like "*%*") {
            $profilePng = [System.Environment]::ExpandEnvironmentVariables($icon)
        } else {
            Write-Host "Invalid profile icon found $icon. Please report an issue at https://github.com/lextm/windowsterminal-shell/issues ."
        }
    }

    if (($null -eq $profilePng) -or -not (Test-Path $profilePng)) {
        # fallback to profile PNG
        $profilePng = "$folderProfileIcons$guid.scale-200.png"
        if (-not (Test-Path($profilePng))) {
            if ($profile.source -eq "Windows.Terminal.Wsl") {
                $profilePng = "$folderProfileIcons{9acb9455-ca41-5af7-950f-6bca1bc9722f}.scale-200.png"
            }
        }
    }

    if (Test-Path $profilePng) {        
        if ($profilePng -like "*.png") {
            # found PNG, convert to ICO
            $result = "$localCache$guid.ico"
            ConvertTo-Icon -File $profilePng -OutputFile $result
        } elseif ($profilePng -like "*.ico") {
            $result = $profilePng
        } else {
            Write-Warning "Icon format is not supported by this script $profilePng. Please use PNG or ICO format."
        }
    } else {
        Write-Warning "Didn't find icon for profile $name."
    }

    if ($null -eq $result) {
        # final fallback
        $result = $defaultIcon
    }

    return $result
}

function CreateMenuItem(
    [Parameter(Mandatory=$true)]
    [string]$rootKey,
    [Parameter(Mandatory=$true)]
    [string]$name,
    [Parameter(Mandatory=$true)]
    [string]$icon,
    [Parameter(Mandatory=$true)]
    [string]$command,
    [Parameter(Mandatory=$true)]
    [bool]$elevated
)
{
    New-Item -Path $rootKey -Force | Out-Null
    New-ItemProperty -Path $rootKey -Name 'MUIVerb' -PropertyType String -Value $name | Out-Null
    New-ItemProperty -Path $rootKey -Name 'Icon' -PropertyType String -Value $icon | Out-Null
    if ($elevated) {
        New-ItemProperty -Path $rootKey -Name 'HasLUAShield' -PropertyType String -Value '' | Out-Null
    }

    New-Item -Path "$rootKeycommand" -Force | Out-Null
    New-ItemProperty -Path "$rootKeycommand" -Name '(Default)' -PropertyType String -Value $command | Out-Null
}

function CreateProfileMenuItems(
    [Parameter(Mandatory=$true)]
    $profile,
    [Parameter(Mandatory=$true)]
    [string]$executable,
    [Parameter(Mandatory=$true)]
    [string]$folder,
    [Parameter(Mandatory=$true)]
    [string]$localCache,
    [Parameter(Mandatory=$true)]
    [string]$icon,
    [Parameter(Mandatory=$true)]
    [string]$layout,
    [Parameter(Mandatory=$true)]
    [bool]$isPreview,
    [bool]$isScoop)
{
    $guid = $profile.guid
    $name = $profile.name
    $command = """$executable"" -p ""$name"" -d ""%V."""
    $elevated = "wscript.exe ""$localCache/helper.vbs"" ""$executable"" ""%V."" ""$name"""
    $profileIcon = GetProfileIcon $profile $folder $localCache $icon $isPreview

    if ($layout -eq "Default") {
        $rootKey = "Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryContextMenusMenuTerminalshell$guid"
        $rootKeyElevated = "Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryContextMenusMenuTerminalAdminshell$guid"
        CreateMenuItem $rootKey $name $profileIcon $command $false
        CreateMenuItem $rootKeyElevated $name $profileIcon $elevated $true
    } elseif ($layout -eq "Flat") {
        CreateMenuItem "Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminal_$guid" "$name here" $profileIcon $command $false
        CreateMenuItem "Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminalAdmin_$guid" "$name here as administrator" $profileIcon $elevated $true   
        CreateMenuItem "Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryBackgroundshellMenuTerminal_$guid" "$name here" $profileIcon $command $false
        CreateMenuItem "Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryBackgroundshellMenuTerminalAdmin_$guid" "$name here as administrator" $profileIcon $elevated $true   
    }
}

function CreateMenuItems(
    [Parameter(Mandatory=$true)]
    [string]$executable,
    [Parameter(Mandatory=$true)]
    [string]$layout,
    [Parameter(Mandatory=$true)]
    [bool]$includePreview)
{
    $folder = GetProgramFilesFolder $includePreview
    $localCache = "$Env:LOCALAPPDATAMicrosoftWindowsAppsCache"

    if (-not (Test-Path $localCache)) {
        New-Item $localCache -ItemType Directory | Out-Null
    }

    Generate-HelperScript $localCache
    $icon = GetWindowsTerminalIcon $folder $localCache

    if ($layout -eq "Default") {
        # defaut layout creates two menus
        New-Item -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminal' -Force | Out-Null
        New-ItemProperty -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminal' -Name 'MUIVerb' -PropertyType String -Value 'Windows Terminal here' | Out-Null
        New-ItemProperty -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminal' -Name 'Icon' -PropertyType String -Value $icon | Out-Null
        New-ItemProperty -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminal' -Name 'ExtendedSubCommandsKey' -PropertyType String -Value 'Directory\ContextMenus\MenuTerminal' | Out-Null

        New-Item -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryBackgroundshellMenuTerminal' -Force | Out-Null
        New-ItemProperty -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryBackgroundshellMenuTerminal' -Name 'MUIVerb' -PropertyType String -Value 'Windows Terminal here' | Out-Null
        New-ItemProperty -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryBackgroundshellMenuTerminal' -Name 'Icon' -PropertyType String -Value $icon | Out-Null
        New-ItemProperty -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryBackgroundshellMenuTerminal' -Name 'ExtendedSubCommandsKey' -PropertyType String -Value 'Directory\ContextMenus\MenuTerminal' | Out-Null

        New-Item -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryContextMenusMenuTerminalshell' -Force | Out-Null

        New-Item -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminalAdmin' -Force | Out-Null
        New-ItemProperty -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminalAdmin' -Name 'MUIVerb' -PropertyType String -Value 'Windows Terminal here as administrator' | Out-Null
        New-ItemProperty -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminalAdmin' -Name 'Icon' -PropertyType String -Value $icon | Out-Null
        New-ItemProperty -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminalAdmin' -Name 'ExtendedSubCommandsKey' -PropertyType String -Value 'Directory\ContextMenus\MenuTerminalAdmin' | Out-Null

        New-Item -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryBackgroundshellMenuTerminalAdmin' -Force | Out-Null
        New-ItemProperty -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryBackgroundshellMenuTerminalAdmin' -Name 'MUIVerb' -PropertyType String -Value 'Windows Terminal here as administrator' | Out-Null
        New-ItemProperty -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryBackgroundshellMenuTerminalAdmin' -Name 'Icon' -PropertyType String -Value $icon | Out-Null
        New-ItemProperty -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryBackgroundshellMenuTerminalAdmin' -Name 'ExtendedSubCommandsKey' -PropertyType String -Value 'Directory\ContextMenus\MenuTerminalAdmin' | Out-Null

        New-Item -Path 'Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryContextMenusMenuTerminalAdminshell' -Force | Out-Null
    } elseif ($layout -eq "Mini") {
        $command = """$executable"" -d ""%V."""
        $elevated = "wscript.exe ""$localCache/helper.vbs"" ""$executable"" ""%V."""
        CreateMenuItem "Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminalMini" "Windows Terminal here" $icon $command $false
        CreateMenuItem "Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminalAdminMini" "Windows Terminal here as administrator" $icon $elevated $true   
        CreateMenuItem "Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryBackgroundshellMenuTerminalMini" "Windows Terminal here" $icon $command $false
        CreateMenuItem "Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryBackgroundshellMenuTerminalAdminMini" "Windows Terminal here as administrator" $icon $elevated $true   
        return
    }

    $isPreview = $folder -like "*WindowsTerminalPreview*"
    $isScoop = $folder -like "*scoopappswindows-terminal*"
    $profiles = GetActiveProfiles $isPreview $isScoop
    foreach ($profile in $profiles) {
        CreateProfileMenuItems $profile $executable $folder $localCache $icon $layout $isPreview $isScoop
    }
}

# Based on @nerdio01's version in https://github.com/microsoft/terminal/issues/1060

if ((Test-Path "Registry::HKEY_CLASSES_ROOTDirectoryshellMenuTerminal") -and
    -not (Test-Path "Registry::HKEY_CURRENT_USERSOFTWAREClassesDirectoryshellMenuTerminal")) {
    Write-Error "Please execute uninstall.old.ps1 to remove previous installation."
    exit 1
}

if ($PSVersionTable.PSVersion.Major -lt 6) {
    Write-Error "Must be executed in PowerShell 6 and above. Learn how to install it from https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows?view=powershell-7 . Exit."
    exit 1
}

if (Test-Path "$env:USERPROFILEscoopappswindows-terminal") {
        $executable = "$env:USERPROFILEscoopappswindows-terminalcurrentwt.exe"
} else {
        $executable = "$env:LOCALAPPDATAMicrosoftWindowsAppswt.exe"
}

if (-not (Test-Path $executable)) {
    Write-Error "Windows Terminal not detected at $executable. Learn how to install it from https://github.com/microsoft/terminal (via Microsoft Store is recommended). Exit."
    exit 1
}

Write-Host "Use $Layout layout."

CreateMenuItems $executable $Layout $PreRelease

Write-Host "Windows Terminal installed to Windows Explorer context menu."
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/885109.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号