feat: implement Installer Studio MSIX authoring workflow
Add the shared Rust engine, Tauri UI and CLI, registry authoring, developer signing, branded start screen and .isproj persistence. Remove the unused project ID. Validation: frontend build and tests, Rust workspace tests, native build and real Windows SDK package generation passed. Closes #2 Closes #3 Closes #4 Closes #5 Closes #6 Closes #7
This commit is contained in:
1 parent
24b624301c
commit
388e1e3327
103 files changed
+13328
-5
No files matched your search
@@ -0,0 +1,65 @@
|
||||
# 현재 제작기로 EG-BIM MSIX 샘플 생성
|
||||
|
||||
사용자 요청에 따라 InstallShield ISM을 참고하여 현재 MSIX Studio의 입력 프로젝트를 준비하고, GUI와 같은 Rust 엔진을 쓰는 `package-builder` CLI로 생성한다. 별도 스크립트가 MakeAppx를 직접 호출하지 않는다. 제작기 본체의 패키징 코드는 변경하지 않는다.
|
||||
|
||||
## 입력과 변환 범위
|
||||
|
||||
| 항목 | 사용한 값 |
|
||||
| --- | --- |
|
||||
| ISM | `D:\egbim\repo\14.1\InstallShield\src\EG-BIM_V1.13.1.ism` |
|
||||
| 본체 | `D:\egbim\repo\14.1\Build\EG-BIM\EG-BIM.Pro.64bit` |
|
||||
| EgViewer | `D:\egbim\repo\14.1\CoWork\Import\EgViewer` |
|
||||
| 추가 경로 보정 | 같은 저장소의 IntelliCAD 텍스처·brand 아이콘·영문 사전·Tablet 및 CadFonts 리소스 |
|
||||
| 파일 수 | ISM 4,701개, 누락 0개, 표시 아이콘 2개 추가 |
|
||||
| 패키지 정보 | `Baron.EGBIM.Sample`, `CN=Baron MSIX Sample`, `1.13.1.0`, x64 |
|
||||
| 도구 | 현재 CLI + Windows SDK `10.0.26100.0` MakeAppx |
|
||||
|
||||
실제 사용 경로는 파일별 CSV/JSON으로 기록한다. 원본을 수정하거나 하드링크하지 않고 선별한 파일을 별도 payload 폴더에 복사해 해시를 대조한다. ISM에 없는 최신 빌드 파일이나 Debug 결과를 자동으로 섞지 않는다.
|
||||
|
||||
처음에는 파일별 include 패턴을 입력했으나 현재 제작기의 대량 패턴 검사에서 메모리 사용량이 커져 해당 검사를 중단했다. 최종 프로젝트는 준비된 payload 전체를 읽는 규칙과 아이콘 규칙 두 개를 사용한다. 별도 비교로 ISM 파일의 경로·크기·해시와 계획의 정확한 일치를 확인한다. 제작기 전반의 대량 패턴 처리 개선은 이 샘플 작업에서 구현하지 않았다.
|
||||
|
||||
## 실행 경로
|
||||
|
||||
1. `cargo build --locked -p package-builder`로 현재 소스의 CLI를 빌드한다.
|
||||
2. [입력 준비 스크립트](../../src/scripts/Prepare-EgbimMsixSample.py)는 ISM 매핑·payload·프로젝트·미변환 보고서를 만든다.
|
||||
3. [자산 준비 스크립트](../../src/scripts/New-EgbimSampleAssets.ps1)는 기존 Grimi 아이콘에서 PNG를 준비한다.
|
||||
4. [CLI 실행 스크립트](../../src/scripts/Build-EgbimMsixSample.ps1)는 현재 제작기의 `plan release`, `build`를 호출하며 `-Export` 지정 시 `export`도 호출한다.
|
||||
5. 제작기 내부에서 MakeAppx 빌드·역추출·파일 해시와 manifest identity 검사를 수행한다.
|
||||
|
||||
로컬 프로젝트는 `D:\networkSetup\output\samples\egbim-msix-20261022\package-project.json`이다. GUI의 프로젝트 열기에서 같은 파일을 선택할 수 있다. 대용량 payload와 산출물은 `.gitignore`의 `/output/samples/`로 제외한다.
|
||||
|
||||
작업 ID: `e13d4d28-8271-4beb-8241-060eff762247`. 최종 실행 결과는 로컬 `reports/build-result.json`, 내보내기는 `reports/export-result.json`, 도구 출처는 `reports/builder-provenance.json`에 기록한다.
|
||||
|
||||
## 현재 구현의 한계
|
||||
|
||||
실제 빌드 결과는 `ArtifactVerified`, 파일 크기는 **1,923,183,886바이트**다. 제작기 내부의 역추출 및 4,703개 입력 파일 해시 비교가 통과했다. 별도 패키지 목록 검사에서도 ISM 파일 4,701개가 모두 존재함을 확인했다. MSIX의 URI 이스케이프된 파트 이름을 복원하여 한글/공백 경로를 비교했다.
|
||||
|
||||
SHA-256: `67a151d213d5de52ace80e8a5fe50662f2686dca7e7f5d6cc8b63e022ee3a17c`.
|
||||
|
||||
추가 export 작업은 복사·해시 처리 후 OS 호출에서 대기하여 해당 프로세스만 중단했다. 대기 원인은 확정하지 않았다. 결과는 이미 성공한 `releases/e13d4d28-8271-4beb-8241-060eff762247/package.msix`를 사용하며, 빌드 결과를 export 성공으로 표시하지 않는다. 재실행 스크립트에서 export는 선택 옵션으로 두었다.
|
||||
|
||||
- 미서명 개발 결과이며 운영 배포·Store 제출용이 아니다. 인증서 신뢰 등록과 설치/실행 시험은 수행하지 않는다.
|
||||
- ISM의 레지스트리 379행, COM/파일 연결, CustomAction과 선행 런타임 설치는 자동 변환하지 않는다.
|
||||
- EgViewer의 530개 AppData 대상 파일은 `UserDataSeeds/Roaming/Baron/EG-BIM/Tools/EgViewer`에 보존한다. 실제 AppData 복사와 앱 경로 변경은 미구현이다.
|
||||
- 패키지의 파일/해시 검증 통과와 EG-BIM의 실행·도면·플러그인·라이선스 호환성은 별개다.
|
||||
|
||||
## 설치 오류 0x800B010A 후속 조치
|
||||
|
||||
사용자가 연 원본 릴리스는 `unsignedDevelopment`이며 AppxSignature.p7x가 없었다. 설치 가능한 서명본과 패키징 검증용 원본을 구분하도록 안내를 보완했다.
|
||||
|
||||
- [개발용 서명 스크립트](../../src/scripts/Sign-DevelopmentMsix.ps1)를 추가했다. 현재 제작기의 `release.json`과 패키지 해시를 확인하고 별도 복사본에 SignTool로 서명한다. `Build-EgbimMsixSample.ps1 -SignDevelopment`로 연결할 수 있다. GUI/공통 Rust 엔진의 운영 서명 기능은 이번 변경 범위가 아니다.
|
||||
- 실제 서명본: `D:\networkSetup\output\samples\egbim-msix-20261022\signed-test\package.msix`.
|
||||
- Subject: `CN=Baron MSIX Sample`, 지문 `E0444310862C4BF5802FD36AB4AE2DD3F7D12F05`, 만료 2027-01-22 15:50:26 KST.
|
||||
- 개인 키는 `CurrentUser\My`의 내보낼 수 없는 키다. `development-signing.cer`에는 공개 인증서만 포함한다. Microsoft/상용 발급 인증서가 아닌 자체 서명 테스트 인증서다.
|
||||
- SignTool 서명 성공, CMS 서명 검사 성공. 서명본 SHA-256: `a22286f234d0a3bbc7c4a121865154c251fc31c1a684aae3f5ee5eb91d5ca93a`.
|
||||
- 별도 ZIP 스트림 SHA-256 검사에서 입력 4,703개 파일 및 manifest/blockmap 총 4,705개 항목이 원본과 동일했다. 원본 패키지 해시도 유지됐다. 추가 항목은 AppxSignature.p7x와 AppxMetadata/CodeIntegrity.cat이며 content type 변경을 제외한 기존 항목은 변경되지 않았다. 두 PowerShell 스크립트의 구문 검사도 통과했다.
|
||||
- SignTool verify는 인증서 미신뢰로 실패했다. 현재 도구 세션이 관리자 권한이 아니어서 컴퓨터 신뢰 저장소는 변경하지 않았다. 서명본 폴더 README에 관리자 PowerShell 등록 명령과 재검증 명령을 제공했다.
|
||||
- 설치·앱 실행 시험은 미수행이며 `deploymentReady=false`를 유지한다. 원본 릴리스와 기존 호환성 제약도 유지한다.
|
||||
|
||||
근거: [Microsoft — 테스트 인증서 생성 및 Trusted People 등록](https://learn.microsoft.com/en-us/windows/msix/package/create-certificate-package-signing), [Microsoft — SignTool MSIX 서명](https://learn.microsoft.com/en-us/windows/msix/package/sign-app-package-using-signtool).
|
||||
|
||||
### 동일 오류 재문의: 이 PC의 인증서 신뢰 등록 완료
|
||||
|
||||
재문의 시 확인 결과 위 인증서는 `CurrentUser\My`에만 존재했고, `LocalMachine\TrustedPeople`에는 없었다. 공개 CER와 고정 지문·Subject·유효기간을 검사하는 `signed-test/Register-TestCertificate.ps1`을 준비하여 관리자 권한 프로세스로 실행했다. 해당 인증서 하나를 `LocalMachine\TrustedPeople`에 등록했으며 루트 저장소는 변경하지 않았다.
|
||||
|
||||
등록 후 Windows SDK SignTool `verify /pa /v`가 종료 코드 0으로 통과했다(검증 1개, 경고 0개, 오류 0개). 등록 결과는 `certificate-registration.json`, 최신 검증은 `trust-verification.json`과 `verify-after-trust.log`에 기록했다. 기존 `signing-result.json`과 `verify.log`는 등록 전 기록으로 보존한다. 설치·앱 실행 시험과 운영 배포 승인은 별개이며 아직 수행하지 않았다.
|
||||
@@ -0,0 +1,75 @@
|
||||
# MSIX 레지스트리 설정 편집 및 빌드 반영
|
||||
|
||||
현재 MSIX Studio에 **레지스트리** 탭을 추가했다. 항목 추가·수정·삭제를 프로젝트 JSON에 저장하며, CLI와 GUI가 사용하는 공통 Rust 빌드 엔진에서 실제 `registry.dat`를 생성한다. 설정을 입력만 받고 빌드에서 무시하는 기능이 아니다.
|
||||
|
||||
## 사용 방법
|
||||
|
||||
1. 새로 빌드한 `src/target/debug/msix-studio.exe`를 실행하고 프로젝트를 연다.
|
||||
2. **레지스트리 → 레지스트리 값 추가**를 누른다.
|
||||
3. 키 경로, 값 이름, 32/64비트 뷰, 값 형식, 데이터를 입력한다. 값 이름을 비우면 해당 키의 기본값이다.
|
||||
4. 저장한 뒤 **검증 · 빌드 → 입력 검사 → 빌드 계획 생성 → MSIX 빌드**를 실행한다.
|
||||
5. 릴리스의 `registry-report.json`에서 항목 수, 패키지 내부 경로와 검증 결과를 확인한다.
|
||||
|
||||
현재 직접 빌드한 실행 파일에는 새 UI가 포함된다. 이미 실행 중이던 제작기는 종료 후 새 실행 파일로 다시 열어야 한다. GUI 클릭 시각 검사는 자동 수행하지 않았으며, 프런트엔드 빌드와 편집기 렌더링 테스트를 수행했다.
|
||||
|
||||
## 지원하는 설정
|
||||
|
||||
앱 전용 `HKLM\Software\회사\제품` 설정을 지원한다. `registry.dat`는 호스트 레지스트리에 가져오지 않으며 패키지 앱이 보는 레지스트리 뷰에 포함된다. 외부 앱이나 시스템 전체에 적용할 설정을 등록하는 방식이 아니다.
|
||||
|
||||
| 형식 | 데이터 입력 |
|
||||
| --- | --- |
|
||||
| `REG_SZ` | 문자열 그대로, 한글과 빈 문자열 지원 |
|
||||
| `REG_EXPAND_SZ` | `%LOCALAPPDATA%` 등의 환경 변수 표기를 보존; 제작 PC에서 확장하지 않음 |
|
||||
| `REG_DWORD` | 0~4294967295, 10진수 또는 `0x` 16진수 |
|
||||
| `REG_QWORD` | 0~18446744073709551615, JSON 문자열로 저장하여 JavaScript 정밀도 손실 방지 |
|
||||
| `REG_MULTI_SZ` | 한 줄에 한 문자열, 빈 줄 거부; 전체 빈 데이터는 빈 목록 |
|
||||
| `REG_BINARY` | `00 FF 12` 또는 `00FF12`; 빈 데이터 지원 |
|
||||
|
||||
64비트 뷰는 hive 안의 `REGISTRY\MACHINE\SOFTWARE\...`, 32비트 뷰는 `REGISTRY\MACHINE\SOFTWARE\WOW6432Node\...`로 저장한다. 키 입력에서 WOW6432Node를 중복 지정할 수 없다. 이 뷰 선택은 앱 고유 Software 키용이며 Windows 공유 키·특수 리디렉션 규칙 전체를 자동 분석하지 않는다.
|
||||
|
||||
항목 ID, 키와 이름의 중복, 형식별 데이터, 숫자 범위, NUL, 잘못된 키 경로를 검사한다. 키와 값 이름의 중복은 대소문자를 구분하지 않는다. 항목은 10,000개, 입력 데이터는 값당 UTF-8 1 MiB까지다.
|
||||
|
||||
## 프로젝트 계약
|
||||
|
||||
v2 프로젝트에 선택 필드 `registry`를 추가했다. 기존 파일에 필드가 없으면 빈 목록으로 연다. 프로젝트 저장·백업·계획 revision 검사는 기존 흐름을 그대로 사용하므로 설정 변경 후에는 새 빌드 계획이 필요하다. JSON Schema도 갱신했다.
|
||||
|
||||
```json
|
||||
{
|
||||
"registry": [
|
||||
{
|
||||
"id": "baron-language",
|
||||
"hive": "HKLM",
|
||||
"key": "Software\\Baron\\EG-BIM",
|
||||
"name": "Language",
|
||||
"view": "64",
|
||||
"valueType": "REG_SZ",
|
||||
"data": "ko-KR"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
위 내용은 프로젝트에 넣는 부분 예시다. 문자열은 literal이며 `[INSTALLDIR]`, `[APPDIR]` 같은 MSI 속성을 자동 치환하지 않는다. MSIX 설치 폴더는 버전별로 달라질 수 있으므로 기존 ISM의 경로 문자열을 그대로 가져오면 안 된다.
|
||||
|
||||
## 구현과 검증
|
||||
|
||||
- 도메인: `package-domain/src/registry.rs`에서 설정·검증·바이트 인코딩을 담당한다.
|
||||
- 빌드: 시스템 디렉터리의 `offreg.dll`을 제한된 DLL 검색 방식으로 로드한다. Microsoft Offline Registry API로 메모리 hive를 생성하고 저장한다. 관리자 권한이나 호스트 레지스트리 마운트는 사용하지 않는다. DLL이 없으면 명시적으로 실패한다.
|
||||
- 검증: 저장한 hive를 다시 열어 값 형식과 바이트를 비교하고, MakeAppx 역추출 후 hive 해시와 값들을 다시 확인한다.
|
||||
- `registry.dat`, `User.dat`, `User.Classes.dat`를 파일 입력으로 덮어쓰는 경로는 거부한다.
|
||||
- 보고서: `registry-report.json`을 작업·릴리스·내보내기에 포함한다. 이전 릴리스에 보고서가 없어도 내보내기는 가능하다. 빈 설정은 `notRequested`, 반영 후 비교 통과는 `verified`다.
|
||||
- 앱에서 수정한 사용자별 값의 업데이트 병합이나 제거 정책은 이번 기능에서 별도 보장하지 않는다.
|
||||
|
||||
## 실제 시험 결과
|
||||
|
||||
- Rust workspace 단위/통합 테스트: 통과. 기존 프로젝트 호환, 저장·삭제, QWORD 정밀도, Unicode, 중복·경로·예약 파일 차단, 오프라인 hive 생성·읽기·불일치·취소 검사 포함.
|
||||
- 프런트엔드 TypeScript/Vite 빌드 및 6개 테스트: 통과. 마크업 이스케이프와 삭제 후 행 주소를 확인했다.
|
||||
- Windows SDK MakeAppx 실제 통합 테스트: 두 제품의 패키징·역추출·레지스트리 검증·보고서 내보내기 통과.
|
||||
- 실제 설치/실행 시험: 독립 테스트 identity `Baron.RegistryFeatureProbe20261022`를 현 테스트 인증서로 서명하여 설치했다. 패키지 ID가 있는 프로세스에서 Win32 Registry API로 7개 값을 읽었고, 한글 기본값·32비트 뷰·6가지 형식 모두 기대한 타입/바이트와 일치했다. 이후 해당 테스트 패키지만 제거했다.
|
||||
- 테스트 일반 레지스트리 키는 시험 전후 모두 없었다. 새 인증서를 추가하거나 기존 EG-BIM 앱을 설치·제거하지 않았다.
|
||||
- 실행 시험 원본: `src/fixtures/registry-probe.rs`. 로컬 증빙: `output/samples/registry-feature-test/runtime-result.txt`, `cleanup-result.json`, 릴리스 `registry-report.json`.
|
||||
- EG-BIM ISM의 379개 항목 자동 가져오기·변환 및 EG-BIM 재패키징은 수행하지 않았다. 기존 EG-BIM 서명 샘플에는 이번 설정이 소급 적용되지 않는다.
|
||||
|
||||
HKCU/User.dat, HKCR 별칭, COM/파일 연결 매니페스트, 레지스트리 삭제 작업, 빈 키만 생성, 조건부 설정, `.reg`/ISM 가져오기는 후속 범위다. 현재 단계에서 지원하지 않는 hive와 값 형식은 빌드 전에 거부한다.
|
||||
|
||||
근거: [Microsoft MSIX 레지스트리 동작](https://learn.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-behind-the-scenes), [Offline Registry API](https://learn.microsoft.com/en-us/windows/win32/devnotes/offline-registry-library-functions), [ORSetValue](https://learn.microsoft.com/en-us/windows/win32/devnotes/orsetvalue), [ORSaveHive](https://learn.microsoft.com/en-us/windows/win32/devnotes/orsavehive).
|
||||
@@ -0,0 +1,53 @@
|
||||
# 개발자 서명 모드
|
||||
|
||||
2026-10-23. Rust 공통 엔진과 Tauri 서명 탭에 테스트용 자체 서명 모드를 추가했다. 여기서 개발자 서명은 유료 Microsoft 서명 서비스가 아니라 현재 사용자 저장소의 자체 서명 인증서를 사용하는 기능이다. Windows 개발자 모드와는 별개다.
|
||||
|
||||
## 사용
|
||||
|
||||
1. 패키지 설정에서 Publisher를 확정한다. 예: `CN=Baron MSIX Sample`.
|
||||
2. 서명 탭에서 **개발자 서명 · 테스트용 자체 서명**을 선택한다.
|
||||
3. 테스트 인증서를 생성하거나 목록에서 기존 인증서를 선택한다. 생성과 선택 결과는 로컬 설정에 저장한다.
|
||||
4. 검증·빌드 탭에서 Windows SDK MakeAppx.exe를 연결하고 새 계획을 생성한 뒤 빌드한다. 같은 폴더의 SignTool.exe를 사용한다.
|
||||
5. 결과의 공개 CER를 확인하고 설치할 테스트 PC에서 `Install-TestCertificate.ps1`을 관리자 권한으로 실행한다. 등록 대상은 그 인증서 하나이며 `LocalMachine\TrustedPeople`에 추가한다. 제작기는 등록이나 앱 설치를 자동 실행하지 않는다.
|
||||
|
||||
모드 선택 자체가 테스트용 서명 활성화다. 별도 Windows 개발자 모드나 전역 테스트 모드 토글은 요구하지 않는다. 이후 빌드에는 선택한 인증서를 재사용한다. 새 인증서는 3개월 유효하며 개인 키는 내보낼 수 없도록 생성한다. 인증서가 만료되거나 Publisher가 바뀌면 선택을 다시 해야 한다. 새 인증서를 선택하면 테스트 PC의 신뢰 등록도 별도로 필요하다.
|
||||
|
||||
## 모델과 실행
|
||||
|
||||
- 프로젝트: `signing.mode = unsigned | development`; 필드가 없는 기존 프로젝트는 unsigned.
|
||||
- 로컬: `developerCertificateThumbprint`; 개인 키와 PFX 비밀번호를 프로젝트에 저장하지 않는다.
|
||||
- 계획: 인증서 지문·DER SHA-256·만료일과 SignTool 경로·SHA-256을 고정한다. 빌드 직전에 다시 검사한다.
|
||||
- 인증서: 현재 사용자 My 저장소, 개인 키 보유, Subject/Issuer 일치, 정확한 Publisher 일치, 코드 서명 EKU, 유효 기간을 검사한다.
|
||||
- 빌드: MakeAppx → SignTool SHA-256 패키지 서명 → CMS 서명과 서명자 검사 → WinVerifyTrust → 역추출 및 기존 파일·identity·registry.dat 검증.
|
||||
- WinVerifyTrust 성공 또는 자체 서명 루트 미신뢰 오류 `0x800B0109`만 허용한다. 후자는 `notTrusted`로 보고한다. 다른 검증 오류는 실패 처리한다.
|
||||
- 결과: `selfSignedDevelopment`, `signingReport`와 공개 CER·등록 스크립트·서명 로그. 내보내기에도 포함한다. 설치 시험은 `notRun`, 일반 배포 준비는 false로 유지한다.
|
||||
- 기존 미서명 모드와 운영 서명 프로필 미지원 정책은 유지한다. 내부 EXE/DLL 개별 서명, 타임스탬프와 자동 인증서 갱신은 범위 밖이다.
|
||||
|
||||
CLI 예시:
|
||||
|
||||
```powershell
|
||||
package-builder.exe certificate --project D:\packages\demo\package-project.json --create
|
||||
package-builder.exe certificate --project D:\packages\demo\package-project.json
|
||||
package-builder.exe certificate --project D:\packages\demo\package-project.json --thumbprint <40자리 지문>
|
||||
```
|
||||
|
||||
CLI 사용 전 프로젝트의 signing.mode를 development로 저장한다. 인증서를 선택하지 않았거나 사용할 수 없는 경우 오류를 표시하며 미서명으로 자동 전환하지 않는다.
|
||||
|
||||
## 확인 결과
|
||||
|
||||
- Rust 테스트 22개 통과. 별도 Windows SDK 통합 시험은 기존 두 제품의 미서명 빌드·내용 검사·오래된 계획 거부를 확인한다.
|
||||
- 프런트엔드 테스트 8개 통과; TypeScript/Vite 빌드 통과.
|
||||
- 작은 레지스트리 샘플을 이용해 기존 신뢰 인증서와 새 미신뢰 인증서로 각각 실제 서명 MSIX 생성 및 역추출 검증 성공.
|
||||
- 기존 인증서: `trustVerification=passed`, `winVerifyTrust=0x00000000`.
|
||||
- 새 인증서: `trustVerification=notTrusted`, `winVerifyTrust=0x800B0109`, CMS 서명 검증 성공.
|
||||
- Publisher 불일치 인증서 선택 거부, 실패 시 기존 선택 보존, 인증서 재조회, 계획의 인증서 해시 변조 거부, 공개 CER·보고서 내보내기 확인.
|
||||
- 이 시험에서 머신 신뢰 저장소를 변경하거나 앱을 설치하지 않았다. 새 테스트 인증서는 해당 사용자 My 저장소에 남겨 재사용할 수 있다. GUI 화면의 실제 클릭 시험은 수행하지 않았다.
|
||||
- EG-BIM 대용량 샘플은 다시 생성하지 않았다.
|
||||
|
||||
증빙: [시험 결과 JSON](../../src/tests/verification-2026-10-23-developer-signing.json). 샘플 위치: `output/samples/developer-signing-test-20261023`.
|
||||
|
||||
## 근거
|
||||
|
||||
- [Microsoft: 패키지 서명 인증서 만들기](https://learn.microsoft.com/en-us/windows/msix/package/create-certificate-package-signing)
|
||||
- [Microsoft: SignTool로 앱 패키지 서명](https://learn.microsoft.com/en-us/windows/msix/package/sign-app-package-using-signtool)
|
||||
- [Microsoft: WinVerifyTrust](https://learn.microsoft.com/en-us/windows/win32/api/wintrust/nf-wintrust-winverifytrust)
|
||||
Reference in new issue
Block a user