package visual c++ directly in windows installer
This commit is contained in:
parent
d54283d99c
commit
e2064a5784
5 changed files with 141 additions and 12 deletions
21
.github/workflows/oneclient_nightly.yml
vendored
21
.github/workflows/oneclient_nightly.yml
vendored
|
|
@ -132,6 +132,27 @@ jobs:
|
|||
rm -f "$out/OneClient.icns"
|
||||
test -f "$out/Assets.car" || { echo "::error::actool produced no Assets.car"; exit 1; }
|
||||
|
||||
- name: (Windows) Bundle VC++ redistributable into the installer
|
||||
if: matrix.platform == 'windows-latest'
|
||||
shell: bash
|
||||
run: python3 distribution/windows/bundle-vcredist.py
|
||||
|
||||
- name: (Windows) Verify bundled redistributable is Microsoft-signed
|
||||
if: matrix.platform == 'windows-latest'
|
||||
shell: pwsh
|
||||
run: |
|
||||
$sig = Get-AuthenticodeSignature 'target/vcredist/vc_redist.x64.exe'
|
||||
Write-Host "Authenticode status: $($sig.Status)"
|
||||
Write-Host "Signer: $($sig.SignerCertificate.Subject)"
|
||||
if ($sig.Status -ne 'Valid') {
|
||||
Write-Error "vc_redist.x64.exe signature is $($sig.Status), refusing to bundle it"
|
||||
exit 1
|
||||
}
|
||||
if ($sig.SignerCertificate.Subject -notmatch 'O=Microsoft Corporation') {
|
||||
Write-Error "vc_redist.x64.exe is not signed by Microsoft: $($sig.SignerCertificate.Subject)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Package (unsigned)
|
||||
shell: bash
|
||||
env:
|
||||
|
|
|
|||
21
.github/workflows/oneclient_release.yml
vendored
21
.github/workflows/oneclient_release.yml
vendored
|
|
@ -345,6 +345,27 @@ jobs:
|
|||
rm -f "$out/OneClient.icns"
|
||||
test -f "$out/Assets.car" || { echo "::error::actool produced no Assets.car"; exit 1; }
|
||||
|
||||
- name: (Windows) Bundle VC++ redistributable into the installer
|
||||
if: matrix.platform == 'windows-latest'
|
||||
shell: bash
|
||||
run: python3 distribution/windows/bundle-vcredist.py
|
||||
|
||||
- name: (Windows) Verify bundled redistributable is Microsoft-signed
|
||||
if: matrix.platform == 'windows-latest'
|
||||
shell: pwsh
|
||||
run: |
|
||||
$sig = Get-AuthenticodeSignature 'target/vcredist/vc_redist.x64.exe'
|
||||
Write-Host "Authenticode status: $($sig.Status)"
|
||||
Write-Host "Signer: $($sig.SignerCertificate.Subject)"
|
||||
if ($sig.Status -ne 'Valid') {
|
||||
Write-Error "vc_redist.x64.exe signature is $($sig.Status), refusing to bundle it"
|
||||
exit 1
|
||||
}
|
||||
if ($sig.SignerCertificate.Subject -notmatch 'O=Microsoft Corporation') {
|
||||
Write-Error "vc_redist.x64.exe is not signed by Microsoft: $($sig.SignerCertificate.Subject)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Package
|
||||
shell: bash
|
||||
env:
|
||||
|
|
|
|||
81
distribution/windows/bundle-vcredist.py
Normal file
81
distribution/windows/bundle-vcredist.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import hashlib
|
||||
import re
|
||||
import sys
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
REDIST_URL = "https://aka.ms/vs/17/release/vc_redist.x64.exe"
|
||||
BEGIN = "; >>> VC_REDIST_INSTALL >>>"
|
||||
END = "; <<< VC_REDIST_INSTALL <<<"
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
DEFAULT_CARGO_TOML = REPO_ROOT / "packages" / "oneclient_app" / "Cargo.toml"
|
||||
DEFAULT_REDIST = REPO_ROOT / "target" / "vcredist" / "vc_redist.x64.exe"
|
||||
|
||||
BLOCK = """ {begin}
|
||||
; Generated by distribution/windows/bundle-vcredist.py -- do not edit by hand.
|
||||
DetailPrint "Installing Microsoft Visual C++ Redistributable (x64)..."
|
||||
InitPluginsDir
|
||||
File "/oname=$PLUGINSDIR\\\\vc_redist.x64.exe" "{redist}"
|
||||
ExecWait '"$PLUGINSDIR\\\\vc_redist.x64.exe" /quiet /norestart' $R3
|
||||
${{If}} $R3 == 3010
|
||||
SetRebootFlag true
|
||||
${{EndIf}}
|
||||
{end}"""
|
||||
|
||||
REGION = re.compile(
|
||||
r"^[ \t]*" + re.escape(BEGIN) + r".*?^[ \t]*" + re.escape(END) + r"[ \t]*$",
|
||||
re.DOTALL | re.MULTILINE,
|
||||
)
|
||||
|
||||
|
||||
def download(dest: Path) -> None:
|
||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
print(f"downloading {REDIST_URL} -> {dest}")
|
||||
with urllib.request.urlopen(REDIST_URL) as resp, dest.open("wb") as out:
|
||||
while chunk := resp.read(1 << 20):
|
||||
out.write(chunk)
|
||||
|
||||
data = dest.read_bytes()
|
||||
if data[:2] != b"MZ":
|
||||
sys.exit(f"error: {dest} is not a PE image (no MZ header)")
|
||||
if len(data) < 10 * 1024 * 1024:
|
||||
sys.exit(f"error: {dest} is only {len(data)} bytes, expected >10MB")
|
||||
print(f" {len(data)} bytes, sha256={hashlib.sha256(data).hexdigest()}")
|
||||
|
||||
|
||||
def patch(cargo_toml: Path, redist: Path) -> None:
|
||||
text = cargo_toml.read_text(encoding="utf-8")
|
||||
if not REGION.search(text):
|
||||
sys.exit(f"error: {BEGIN} .. {END} region not found in {cargo_toml}")
|
||||
|
||||
block = BLOCK.format(begin=BEGIN, end=END, redist=str(redist).replace("\\", "\\\\"))
|
||||
cargo_toml.write_text(REGION.sub(lambda _: block, text, count=1), encoding="utf-8")
|
||||
print(f"patched {cargo_toml} to embed {redist}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument("--cargo-toml", type=Path, default=DEFAULT_CARGO_TOML)
|
||||
ap.add_argument("--redist", type=Path, default=DEFAULT_REDIST)
|
||||
ap.add_argument(
|
||||
"--skip-download",
|
||||
action="store_true",
|
||||
help="reuse an already-downloaded --redist instead of fetching it",
|
||||
)
|
||||
args = ap.parse_args()
|
||||
|
||||
redist = args.redist.resolve()
|
||||
if args.skip_download:
|
||||
if not redist.is_file():
|
||||
sys.exit(f"error: --skip-download given but {redist} does not exist")
|
||||
else:
|
||||
download(redist)
|
||||
|
||||
patch(args.cargo_toml.resolve(), redist)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -63,7 +63,7 @@ winresource = "=0.1.31"
|
|||
product-name = "OneClient"
|
||||
identifier = "org.polyfrost.OneClient"
|
||||
category = "Game"
|
||||
publisher = "Polyfrost"
|
||||
publisher = "Polyfrost Inc."
|
||||
copyright = "© 2026 Polyfrost Inc."
|
||||
homepage = "https://polyfrost.org/projects/oneclient"
|
||||
long-description = "Next-generation open source Minecraft launcher"
|
||||
|
|
@ -115,17 +115,12 @@ Section "-VCRedist"
|
|||
Goto vcredist_done
|
||||
${EndIf}
|
||||
|
||||
DetailPrint "Installing Microsoft Visual C++ Redistributable (x64)..."
|
||||
nsis_tauri_utils::Download "https://aka.ms/vs/17/release/vc_redist.x64.exe" "$PLUGINSDIR\\vc_redist.x64.exe"
|
||||
Pop $R2
|
||||
${If} $R2 == 0
|
||||
ExecWait '"$PLUGINSDIR\\vc_redist.x64.exe" /quiet /norestart' $R3
|
||||
${If} $R3 == 3010
|
||||
SetRebootFlag true
|
||||
${EndIf}
|
||||
${ElseIf} $PassiveMode != 1
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION "Could not download the Microsoft Visual C++ Redistributable. OneClient may fail to start until you install it manually from https://aka.ms/vs/17/release/vc_redist.x64.exe"
|
||||
; >>> VC_REDIST_INSTALL >>>
|
||||
${If} $PassiveMode != 1
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION "OneClient needs the Microsoft Visual C++ Redistributable (x64) 14.40 or newer. Install it from https://aka.ms/vs/17/release/vc_redist.x64.exe, then run this installer again."
|
||||
${EndIf}
|
||||
; <<< VC_REDIST_INSTALL <<<
|
||||
|
||||
vcredist_done:
|
||||
SectionEnd
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,9 +1,20 @@
|
|||
fn main() {
|
||||
// Embeds the app icon into the Windows executable.
|
||||
// Embeds the app icon and VERSIONINFO into the Windows executable.
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let mut res = winresource::WindowsResource::new();
|
||||
res.set_icon("icons/icon.ico");
|
||||
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
res.set("CompanyName", "Polyfrost Inc.");
|
||||
res.set("ProductName", "OneClient");
|
||||
res.set("FileDescription", "OneClient");
|
||||
res.set("LegalCopyright", "© 2026 Polyfrost Inc.");
|
||||
res.set("OriginalFilename", "oneclient_app.exe");
|
||||
res.set("InternalName", "oneclient_app");
|
||||
res.set("FileVersion", version);
|
||||
res.set("ProductVersion", version);
|
||||
|
||||
res.compile()
|
||||
.expect("failed to embed Windows icon resource");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue