src/InitCompileThings.ps1

function GetAssembly($name, $otherinfo) {
    $n = New-Object System.Reflection.AssemblyName(@($name, $otherinfo) -ne $null -join ",")
    try {
        [System.AppDomain]::CurrentDomain.Load($n).Location
    }
    catch {
        $Error.Remove(0)
    }
}
$referenceAssembies = if ($targetRuntime -eq 'Framework2.0') {
    #_if PSScript
        powershell -version 2.0 -NoProfile -OutputFormat xml -file $PSScriptRoot/RuntimePwsh2.0/RefDlls.ps1 $(if ($noConsole) { '-noConsole' })
    #_else
        #_include_as_value Pwsh2RefDllsGetterCodeStr $PSScriptRoot/RuntimePwsh2.0/RefDlls.ps1
        #_!! powershell -version 2.0 -NoProfile -OutputFormat xml -Command "&{$Pwsh2RefDllsGetterCodeStr}$(if($noConsole){' -noConsole'})"
    #_endif
}
else {
    # 绝不要直接使用 System.Private.CoreLib.dll,因为它是netlib的内部实现,而不是公共API
    # [int].Assembly.Location 等基础类型的程序集也是它。
    GetAssembly "mscorlib"
    if ($PSVersionTable.PSEdition -eq "Core") { GetAssembly "System.Runtime" }
    GetAssembly "System.Management.Automation"

    # If noConsole is true, add System.Windows.Forms.dll and System.Drawing.dll to the reference assemblies
    if ($noConsole) {
        GetAssembly "System.Windows.Forms" $(if ($PSVersionTable.PSEdition -ne "Core") { "Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" })
        GetAssembly "System.Drawing" $(if ($PSVersionTable.PSEdition -ne "Core") { "Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" })
    }
    elseif ($PSVersionTable.PSEdition -eq "Core") {
        GetAssembly "System.Console"
        GetAssembly "Microsoft.PowerShell.ConsoleHost"
    }

    # If in winpwsh, add System.Core.dll to the reference assemblies
    if ($PSVersionTable.PSEdition -ne "Core") {
        GetAssembly "System.Core" "Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        "System.dll" # some furking magic
    }
}

. $PSScriptRoot\BuildFrame.ps1

[string[]]$Constants = @()

$Constants += $threadingModel
if ($lcid) { $Constants += "culture" }
if ($noError) { $Constants += "noError" }
if ($noConsole) { $Constants += "noConsole" }
if ($noOutput) { $Constants += "noOutput" }
if ($resourceParams.version) { $Constants += "version" }
if ($resourceParams.Count) { $Constants += "Resources" }
if ($credentialGUI) { $Constants += "credentialGUI" }
if ($noVisualStyles) { $Constants += "noVisualStyles" }
if ($exitOnCancel) { $Constants += "exitOnCancel" }
if ($UNICODEEncoding) { $Constants += "UNICODEEncoding" }
if ($winFormsDPIAware) { $Constants += "winFormsDPIAware" }
if ($targetRuntime -eq 'Framework2.0') { $Constants += "Pwsh20" }

if (-not $TempDir) {
    $TempDir = $TempTempDir = [System.IO.Path]::GetTempPath() + [System.IO.Path]::GetRandomFileName()
    New-Item -Path $TempTempDir -ItemType Directory | Out-Null
}
$TempDir = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($TempDir)

$Content | Set-Content $TempDir\main.ps1 -Encoding UTF8 -NoNewline
if ($iconFile -match "^(https?|ftp)://") {
    try {
        # 首先尝试从URL中获取文件扩展名
        $urlExtension = [System.IO.Path]::GetExtension([System.Uri]$iconFile).ToLower()

        # 如果URL中没有扩展名,尝试从Content-Type获取
        if (!$urlExtension) {
            $headResponse = Invoke-WebRequest $iconFile -Method Head -ErrorAction SilentlyContinue
            if ($headResponse) {
                $contentType = $headResponse.Headers.'Content-Type'
                if ($contentType) {
                    # 从Content-Type映射到文件扩展名
                    switch -Regex ($contentType) {
                        "image/png" { $urlExtension = ".png" }
                        "image/jpeg|image/jpg" { $urlExtension = ".jpg" }
                        "image/gif" { $urlExtension = ".gif" }
                        "image/bmp" { $urlExtension = ".bmp" }
                        "image/x-icon|image/vnd.microsoft.icon|image/ico" { $urlExtension = ".ico" }
                        "image/svg" { $urlExtension = ".svg" }
                        default { $urlExtension = ".ico" }  # 默认使用.ico
                    }
                }
            }
        }

        # 如果仍然没有扩展名,默认使用.ico
        if (!$urlExtension) { $urlExtension = ".ico" }

        if ($GuestMode) {
            if ((Invoke-WebRequest $iconFile -Method Head -ErrorAction SilentlyContinue).Headers.'Content-Length' -gt 1mb) {
                Write-I18n Error GuestModeIconFileTooLarge $iconFile -Category LimitsExceeded
                throw
            }
            if ($File -match "^ftp://") {
                Write-I18n Error GuestModeFtpNotSupported -Category ReadError
                throw
            }
        }
        $downloadedIconPath = "$TempDir\icon$urlExtension"
        Invoke-WebRequest -ErrorAction Stop -Uri $iconFile -OutFile $downloadedIconPath
        $iconFile = $downloadedIconPath
    }
    catch {
        Write-I18n Error IconFileNotFound $iconFile -Category ReadError
        throw
    }
}
elseif ($iconFile) {
    # retrieve absolute path independent if path is given relative oder absolute
    $iconFile = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($iconFile)

    if (!(Test-Path $iconFile -PathType Leaf)) {
        Write-I18n Error IconFileNotFound $iconFile -Category ReadError
        throw
    }
}

if ($iconFile) {
    # 自动图片转换:检测非 .ico 后缀并自动转换
    $iconExtension = [System.IO.Path]::GetExtension($iconFile).ToLower()
    if ($iconExtension -ne ".ico") {
        Write-I18n Host ConvertingImageToIcon
        $sourceImage = $null
        $iconStream = $null
        $writer = $null

        try {
            Add-Type -AssemblyName System.Drawing

            $sourceImage = [System.Drawing.Image]::FromFile($iconFile)
            $tempIcoPath = [System.IO.Path]::Combine($TempDir, "converted_icon_$([Guid]::NewGuid().ToString()).ico")

            $sizes = @(16, 32, 48, 256)
            $iconStream = New-Object System.IO.MemoryStream
            $writer = New-Object System.IO.BinaryWriter($iconStream)

            $writer.Write([UInt16]0)  # Reserved
            $writer.Write([UInt16]1)  # Type (ICO)
            $writer.Write([UInt16]$sizes.Count)  # Number of images

            $directoryOffset = $iconStream.Position
            $imageDataOffset = $directoryOffset + (16 * $sizes.Count)

            $imageData = @()
            foreach ($size in $sizes) {
                $bitmap = $null
                $graphics = $null
                $pngStream = $null

                try {
                    $bitmap = New-Object System.Drawing.Bitmap($size, $size)
                    $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
                    $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
                    $graphics.DrawImage($sourceImage, 0, 0, $size, $size)

                    $pngStream = New-Object System.IO.MemoryStream
                    $bitmap.Save($pngStream, [System.Drawing.Imaging.ImageFormat]::Png)
                    $pngBytes = $pngStream.ToArray()

                    $imageData += @{
                        Size   = $size
                        Data   = $pngBytes
                        Offset = $imageDataOffset
                        Length = $pngBytes.Length
                    }
                    $imageDataOffset += $pngBytes.Length
                }
                finally {
                    if ($graphics) { $graphics.Dispose() }
                    if ($pngStream) { $pngStream.Dispose() }
                    if ($bitmap) { $bitmap.Dispose() }
                }
            }

            foreach ($imgData in $imageData) {
                $size = $imgData.Size
                $width = if ($size -eq 256) { 0 } else { $size }
                $height = if ($size -eq 256) { 0 } else { $size }

                $writer.Write([Byte]$width)
                $writer.Write([Byte]$height)
                $writer.Write([Byte]0)
                $writer.Write([Byte]0)
                $writer.Write([UInt16]1)
                $writer.Write([UInt16]32)
                $writer.Write([UInt32]$imgData.Length)
                $writer.Write([UInt32]$imgData.Offset)
            }

            foreach ($imgData in $imageData) {
                $writer.Write($imgData.Data)
            }

            $writer.Flush()
            [System.IO.File]::WriteAllBytes($tempIcoPath, $iconStream.ToArray())

            $iconFile = $tempIcoPath
            Write-I18n Host ImageConvertedToIcon $iconFile

        }
        catch {
            Write-I18n Warning ImageConversionFailed $_.Exception.Message
            Write-I18n Warning PleaseUseIcoFile $iconExtension
            # 转换失败时继续使用原文件,但可能会在后续步骤中失败
        }
        finally {
            if ($writer) { $writer.Dispose() }
            if ($iconStream) { $iconStream.Dispose() }
            if ($sourceImage) { $sourceImage.Dispose() }
        }
    }
}