支持使用 clang-cl 编译 (#1195)

* chore: native 项目支持 clang-cl

* chore: 修复 clang 编译错误

* chore: 修复部分 clang 编译警告

* chore: 修复警告

* chore: 修复所有警告,优化 llvm 查找

* chore: 启用 LTO

* chore: 支持 ARM64

* chore: _ConanDeps 支持 clang-cl

* chore: 编译选项改变 _ConanDeps 自动重新编译

* chore: profile 更改时重新编译 _ConanDeps

* chore: 将 hu 和 ka 加入项目文件,但不参与生成
否则不参与批量替换

* chore: Magpie 项目支持并行编译

* chore: 添加几个提高性能的编译选项

* chore: 优化 _ConanDeps

* chore: publish.py 支持参数

* chore: CI 支持 clang 编译

* chore: 修复 CI 的 conan 缓存

* chore: 优化编译选项,修复 CI

* chore: 修复 CI

* chore: 改变参数顺序

* chore: 添加编译选项支持针对当前硬件生成优化代码

* chore: 优化 CI 脚本

* chore: publish.py 添加 --use-native-march 选项

* chore: 脚本集中在 scripts 文件夹,msbuild 启用并行编译

* chore: clang, x64 配置启用 CX16 指令

* chore: 更新依赖

* chore: 更新格式设置

* chore: 增加额外的斜杠以提高兼容性

* chore: 修复效果文件复制
This commit is contained in:
Xu 2025-07-15 17:40:04 +08:00 committed by GitHub
commit 04ff6ea0a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
71 changed files with 558 additions and 404 deletions

View file

@ -9,8 +9,11 @@ cpp_generate_documentation_comments = xml
# Visual C++ 格式设置
indent_style = tab
indent_size = 4
tab_width= 4
cpp_indent_braces = false
cpp_indent_multi_line_relative_to = statement_begin
cpp_indent_multi_line_relative_to = innermost_parenthesis
cpp_indent_within_parentheses = indent
cpp_indent_preserve_within_parentheses = false
cpp_indent_case_contents = true
@ -21,7 +24,7 @@ cpp_indent_goto_labels = one_left
cpp_indent_preprocessor = leftmost_column
cpp_indent_access_specifiers = false
cpp_indent_namespace_contents = false
cpp_indent_preserve_comments = true
cpp_indent_preserve_comments = false
cpp_new_line_before_open_brace_namespace = same_line
cpp_new_line_before_open_brace_type = same_line
cpp_new_line_before_open_brace_function = same_line
@ -66,4 +69,17 @@ cpp_space_around_binary_operator = insert
cpp_space_around_assignment_operator = insert
cpp_space_pointer_reference_alignment = left
cpp_space_around_ternary_operator = insert
cpp_use_unreal_engine_macro_formatting = true
cpp_wrap_preserve_blocks = one_liners
# Visual C++ 包含清理设置
cpp_include_cleanup_add_missing_error_tag_type = none
cpp_include_cleanup_remove_unused_error_tag_type = dimmed
cpp_include_cleanup_optimize_unused_error_tag_type = suggestion
cpp_include_cleanup_sort_after_edits = false
cpp_sort_includes_error_tag_type = suggestion
cpp_sort_includes_priority_case_sensitive = false
cpp_sort_includes_priority_style = quoted
cpp_includes_style = default
cpp_includes_use_forward_slash = true

View file

@ -11,6 +11,7 @@ jobs:
runs-on: windows-latest
strategy:
matrix:
compiler: ["MSVC", "ClangCL"]
platform: ["x64", "ARM64"]
steps:
@ -27,10 +28,10 @@ jobs:
uses: actions/cache@v4
with:
path: ~/.conan2/p
key: Conan-${{ hashFiles('src/**/conanfile.txt') }}-${{ matrix.platform }}
key: Conan-${{ hashFiles('src/**/conanfile.txt') }}-${{ matrix.compiler }}-${{ matrix.platform }}
- name: Build
run: python publish.py ${{ matrix.platform }} unpackaged certs\Magpie.pfx "${{ secrets.MAGPIE_PFX_PASSWORD }}"
run: python scripts/publish.py --compiler=${{ matrix.compiler }} --platform=${{ matrix.platform }} --pfx-path=certs\Magpie.pfx --pfx-password="${{ secrets.MAGPIE_PFX_PASSWORD }}"
- name: Save hash
id: hash
@ -39,5 +40,5 @@ jobs:
- name: Store build
uses: actions/upload-artifact@v4
with:
name: Magpie-dev-${{ steps.hash.outputs.sha_short }}-${{ matrix.platform }}
name: Magpie-dev-${{ steps.hash.outputs.sha_short }}-${{ matrix.compiler }}-${{ matrix.platform }}
path: ./publish/${{ matrix.platform }}

View file

@ -54,12 +54,7 @@ jobs:
echo "tag=$tag" >> $env:GITHUB_OUTPUT
- name: Build
run: python publish.py ${{ matrix.platform }} unpackaged certs\Magpie.pfx "${{ secrets.MAGPIE_PFX_PASSWORD }}"
env:
MAJOR: ${{ inputs.major }}
MINOR: ${{ inputs.minor }}
PATCH: ${{ inputs.patch }}
TAG: ${{ steps.tag.outputs.tag }}
run: python scripts/publish.py --compiler=ClangCL --platform=${{ matrix.platform }} --version-major=${{ inputs.major }} --version-minor=${{ inputs.minor }} --version-patch=${{ inputs.patch }} --version-tag=${{ steps.tag.outputs.tag }} --pfx-path=certs\Magpie.pfx --pfx-password="${{ secrets.MAGPIE_PFX_PASSWORD }}"
- name: Store artifacts
uses: actions/upload-artifact@v4
@ -85,11 +80,4 @@ jobs:
path: publish
- name: Publish release
run: python ci/release.py
env:
MAJOR: ${{ inputs.major }}
MINOR: ${{ inputs.minor }}
PATCH: ${{ inputs.patch }}
TAG: ${{ needs.build.outputs.tag }}
PRERELEASE: ${{ inputs.prerelease }}
ACCESS_TOKEN: ${{ secrets.CONTENTS_ACCESS_TOKEN }}
run: python scripts/release.py ${{ inputs.major }} ${{ inputs.minor }} ${{ inputs.patch }} ${{ needs.build.outputs.tag }} ${{ inputs.prerelease }} ${{ secrets.CONTENTS_ACCESS_TOKEN }}

View file

@ -17,6 +17,4 @@ jobs:
python-version: '3.11'
- name: Upload documentations to wiki
run: python ci/wiki.py
env:
ACCESS_TOKEN: ${{ secrets.CONTENTS_ACCESS_TOKEN }}
run: python scripts/wiki.py ${{ secrets.CONTENTS_ACCESS_TOKEN }}

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Configuration">
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
<PreferredToolArchitecture Condition="'$(PreferredToolArchitecture)' == ''">x64</PreferredToolArchitecture>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
@ -13,20 +13,10 @@
<SDLCheck>true</SDLCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WarningLevel>Level4</WarningLevel>
<!-- /await:strict: 禁用协程的非标准语言扩展 -->
<!-- /utf-8: 源代码使用 UTF-8 格式 -->
<!-- /Zc:__cplusplus: 更新 __cplusplus 宏 -->
<!-- /volatile:iso: 禁用 volatile 的语义扩展 -->
<!-- /fp:contract: 生成浮点收缩指令。浮点收缩指令是将两个浮点操作合并为一个指令的机器指令,例如 Fused-Multiply-Add (FMA) -->
<!-- fp:contract 可以和其他 fp 选项同时存在,因此每个项目可以分别指定自己的浮点模型 -->
<AdditionalOptions>%(AdditionalOptions) /await:strict /utf-8 /Zc:__cplusplus /volatile:iso /fp:contract</AdditionalOptions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<!-- /Gw: 链接时删除未使用和重复的数据,可以减小二进制文件体积 -->
<!-- /Zc:checkGwOdr: 防止 /Gw 导致某些 ODR 违规被忽略 -->
<AdditionalOptions>%(AdditionalOptions) /Gw /Zc:checkGwOdr</AdditionalOptions>
<AdditionalOptions>/utf-8 /Zc:__cplusplus /volatile:iso %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
</ItemDefinitionGroup>
</Project>

View file

@ -2,34 +2,29 @@ import sys
import os
import subprocess
import glob
import shutil
from xml.etree import ElementTree
import re
import argparse
majorVersion = None
try:
# https://docs.github.com/en/actions/learn-github-actions/variables
if os.environ["GITHUB_ACTIONS"].lower() == "true":
# 不知为何在 Github Actions 中运行时默认编码为 ANSI并且 print 需刷新流才能正常显示
for stream in [sys.stdout, sys.stderr]:
stream.reconfigure(encoding="utf-8")
# 存在 MAJOR 环境变量则发布新版本
majorVersion = os.environ["MAJOR"]
except:
pass
platform = "x64"
if len(sys.argv) >= 2:
platform = sys.argv[1]
if not platform in ["x64", "ARM64"]:
raise Exception("非法参数")
if majorVersion != None:
import re
minorVersion = os.environ["MINOR"]
patchVersion = os.environ["PATCH"]
tag = os.environ["TAG"]
argParser = argparse.ArgumentParser()
argParser.add_argument("--compiler", choices=["MSVC", "ClangCL"], default="MSVC")
argParser.add_argument("--platform", choices=["x64", "ARM64"], default="x64")
argParser.add_argument("--use-native-march", action="store_true")
argParser.add_argument("--version-major", type=int, default=0)
argParser.add_argument("--version-minor", type=int, default=0)
argParser.add_argument("--version-patch", type=int, default=0)
argParser.add_argument("--version-tag", default="")
argParser.add_argument("--pfx-path", default="")
argParser.add_argument("--pfx-password", default="")
args = argParser.parse_args()
#####################################################################
#
@ -57,16 +52,17 @@ if not os.access(msbuildPath, os.X_OK):
#
#####################################################################
os.chdir(os.path.dirname(__file__))
os.chdir(os.path.dirname(__file__) + "\\..")
p = subprocess.run("git rev-parse --short HEAD", capture_output=True)
commitId = str(p.stdout, encoding="utf-8")[0:-1]
if majorVersion != None:
version_props = f";MajorVersion={majorVersion};MinorVersion={minorVersion};PatchVersion={patchVersion};VersionTag={tag}"
versionNumProps = ""
if args.version_major != 0 or args.version_minor != 0 or args.version_patch != 0:
versionNumProps = f";MajorVersion={args.version_major};MinorVersion={args.version_minor};PatchVersion={args.version_patch}"
# 更新 RC 文件中的版本号
version = f"{majorVersion}.{minorVersion}.{patchVersion}.0"
version = f"{args.version_major}.{args.version_minor}.{args.version_patch}.0"
version_comma = version.replace(".", ",")
for project in os.listdir("src"):
rcPath = f"src\\{project}\\{project}.rc"
@ -94,11 +90,11 @@ if majorVersion != None:
f.seek(0)
f.truncate()
f.write(src)
else:
version_props = ""
versionTagProp = "" if args.version_tag == "" else f";VersionTag={args.version_tag}"
p = subprocess.run(
f'"{msbuildPath}" -restore -p:RestorePackagesConfig=true;Configuration=Release;Platform={platform};OutDir={os.getcwd()}\\publish\\{platform}\\;CommitId={commitId}{version_props} Magpie.sln'
f'"{msbuildPath}" Magpie.sln -m -t:Rebuild -restore -p:RestorePackagesConfig=true;Configuration=Release;Platform={args.platform};UseClangCL={args.compiler == "ClangCL"};UseNativeMicroArch={args.use_native_march};OutDir={os.getcwd()}\\publish\\{args.platform}\\;CommitId={commitId}{versionNumProps}{versionTagProp}'
)
if p.returncode != 0:
raise Exception("编译失败")
@ -109,7 +105,7 @@ if p.returncode != 0:
#
#####################################################################
os.chdir("publish\\" + platform)
os.chdir("publish\\" + args.platform)
# 删除文件,忽略错误
@ -132,17 +128,16 @@ print("清理完毕", flush=True)
#
#####################################################################
if len(sys.argv) >= 5 and sys.argv[4] != "":
# sys.argv[2] 保留为打包选项
pfxPath = os.path.join("..\\..", sys.argv[3])
pfxPassword = sys.argv[4]
if args.pfx_path != "":
pfxPath = os.path.join("..\\..", args.pfx_path)
# 取最新的 Windows SDK
windowsSdkDir = max(
glob.glob(programFilesX86Path + "\\Windows Kits\\10\\bin\\10.*")
)
passwordOption = "" if args.pfx_password == "" else f'/p "{args.pfx_password}"'
p = subprocess.run(
f'"{windowsSdkDir}\\x64\\signtool.exe" sign /fd SHA256 /a /f "{pfxPath}" /p "{pfxPassword}" TouchHelper.exe'
f'"{windowsSdkDir}\\x64\\signtool.exe" sign /fd SHA256 /a /f "{pfxPath}" {passwordOption} TouchHelper.exe'
)
if p.returncode != 0:
raise Exception("签名失败")

View file

@ -5,6 +5,7 @@ import shutil
import requests
import hashlib
import json
import argparse
try:
# https://docs.github.com/en/actions/learn-github-actions/variables
@ -15,12 +16,17 @@ try:
except:
pass
majorVersion = os.environ["MAJOR"]
minorVersion = os.environ["MINOR"]
patchVersion = os.environ["PATCH"]
tag = os.environ["TAG"]
isPrerelease = os.environ["PRERELEASE"].lower() == "true"
githubAccessToken = os.environ["ACCESS_TOKEN"]
argParser = argparse.ArgumentParser()
argParser.add_argument("version_major", type=int)
argParser.add_argument("version_minor", type=int)
argParser.add_argument("version_patch", type=int)
argParser.add_argument("tag")
argParser.add_argument("prerelease")
argParser.add_argument("access_token")
args = argParser.parse_args()
isPrerelease = args.prerelease.lower() == "true"
repo = os.environ["GITHUB_REPOSITORY"]
actor = os.environ["GITHUB_ACTOR"]
@ -28,21 +34,21 @@ subprocess.run("git config user.name " + actor)
subprocess.run(f"git config user.email {actor}@users.noreply.github.com")
subprocess.run(
f"git remote set-url origin https://{githubAccessToken}@github.com/{repo}.git"
f"git remote set-url origin https://{args.access_token}@github.com/{repo}.git"
)
# 打标签
if subprocess.run(f"git tag -a {tag} -m {tag}").returncode != 0:
if subprocess.run(f"git tag -a {args.tag} -m {args.tag}").returncode != 0:
raise Exception("打标签失败")
if subprocess.run("git push origin " + tag).returncode != 0:
if subprocess.run("git push origin " + args.tag).returncode != 0:
raise Exception("推送标签失败")
print("已创建标签 " + tag, flush=True)
print("已创建标签 " + args.tag, flush=True)
headers = {
"Accept": "application/vnd.github+json",
"Authorization": "Bearer " + githubAccessToken,
"Authorization": "Bearer " + args.access_token,
"X-GitHub-Api-Version": "2022-11-28",
}
@ -75,13 +81,13 @@ if prevReleaseTag == None:
body = ""
else:
# 默认发行说明为比较两个 tag
body = f"https://github.com/{repo}/compare/{prevReleaseTag}...{tag}"
body = f"https://github.com/{repo}/compare/{prevReleaseTag}...{args.tag}"
response = requests.post(
f"https://api.github.com/repos/{repo}/releases",
json={
"tag_name": tag,
"name": tag,
"tag_name": args.tag,
"name": args.tag,
"prerelease": isPrerelease,
"body": body,
"discussion_category_name": "Announcements",
@ -99,7 +105,7 @@ os.chdir(os.path.dirname(__file__) + "\\..\\publish")
pkgInfos = {}
for platform in ["x64", "ARM64"]:
# 打包成 zip
pkgName = "Magpie-" + tag + "-" + platform
pkgName = "Magpie-" + args.tag + "-" + platform
shutil.make_archive(pkgName, "zip", pkgName)
pkgName += ".zip"
@ -122,7 +128,7 @@ for platform in ["x64", "ARM64"]:
pkgInfos[platform] = (pkgName, md5)
print("已发布 " + tag, flush=True)
print("已发布 " + args.tag, flush=True)
# 更新 version.json
# 此步应在发布版本之后,因为程序使用 version.json 检查更新
@ -130,15 +136,15 @@ os.chdir("..")
with open("version.json", "w", encoding="utf-8") as f:
json.dump(
{
"version": f"{majorVersion}.{minorVersion}.{patchVersion}",
"tag": tag,
"version": f"{args.version_major}.{args.version_minor}.{args.version_patch}",
"tag": args.tag,
"binary": {
"x64": {
"url": f"https://github.com/{repo}/releases/download/{tag}/{pkgInfos['x64'][0]}",
"url": f"https://github.com/{repo}/releases/download/{args.tag}/{pkgInfos['x64'][0]}",
"hash": pkgInfos["x64"][1],
},
"ARM64": {
"url": f"https://github.com/{repo}/releases/download/{tag}/{pkgInfos['ARM64'][0]}",
"url": f"https://github.com/{repo}/releases/download/{args.tag}/{pkgInfos['ARM64'][0]}",
"hash": pkgInfos["ARM64"][1],
},
},

View file

@ -4,6 +4,7 @@ import tempfile
import glob
import shutil
import subprocess
import argparse
try:
# https://docs.github.com/en/actions/learn-github-actions/variables
@ -14,12 +15,11 @@ try:
except:
pass
if not "ACCESS_TOKEN" in os.environ:
raise Exception("未找到环境变量 ACCESS_TOKEN")
argParser = argparse.ArgumentParser()
argParser.add_argument("access_token")
args = argParser.parse_args()
wikiRepoUrl = os.path.expandvars(
"https://${ACCESS_TOKEN}@github.com/${GITHUB_REPOSITORY}.wiki.git"
)
wikiRepoUrl = f"https://{args.access_token}@github.com/{os.environ["GITHUB_REPOSITORY"]}.wiki.git"
# 创建临时目录
wikiRepoDir = tempfile.mkdtemp()

View file

@ -2,21 +2,26 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- 不要直接修改这些选项,应通过 BuildOptions.props.user 或命令行参数覆盖 -->
<PropertyGroup>
<CommitId></CommitId>
<MajorVersion></MajorVersion>
<MinorVersion></MinorVersion>
<PatchVersion></PatchVersion>
<VersionTag></VersionTag>
<!-- 窗口模式缩放时把用于调整窗口尺寸的辅助窗口标示出来 -->
<DebugBorder>false</DebugBorder>
<!-- 在性能分析器上显示调试信息 -->
<DebugInfoOnOverlay>false</DebugInfoOnOverlay>
<!--使用 composition swapchain 呈现-->
<UseCompSwapchain>false</UseCompSwapchain>
<!-- 使用 clang-cl 编译 -->
<UseClangCL>false</UseClangCL>
<!-- 针对当前硬件生成优化代码,只在使用 clang-cl 编译时有效 -->
<UseNativeMicroArch>false</UseNativeMicroArch>
<!-- 编译为打包应用 (暂不支持) -->
<IsPackaged>false</IsPackaged>
<!-- 窗口模式缩放时把用于调整窗口尺寸的辅助窗口标示出来 -->
<DebugBorder>false</DebugBorder>
<!-- 在性能分析器上显示调试信息 -->
<DebugInfoOnOverlay>false</DebugInfoOnOverlay>
<!--使用 composition swapchain 呈现-->
<UseCompSwapchain>false</UseCompSwapchain>
<CommitId></CommitId>
<MajorVersion></MajorVersion>
<MinorVersion></MinorVersion>
<PatchVersion></PatchVersion>
<VersionTag></VersionTag>
</PropertyGroup>
<!-- 用户自定义编译选项 -->
<Import Project="$(MSBuildThisFileDirectory)BuildOptions.props.user" Condition="Exists('$(MSBuildThisFileDirectory)BuildOptions.props.user')" />
<Import Project="$(MSBuildThisFileDirectory)\BuildOptions.props.user" Condition="Exists('$(MSBuildThisFileDirectory)\BuildOptions.props.user')" />
</Project>

View file

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<PropertyGroup Condition="'$(Configuration)' == 'Debug'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<PropertyGroup Condition="'$(Configuration)' == 'Release'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
@ -15,24 +15,34 @@
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<PreprocessorDefinitions>_WINDOWS;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;WINRT_NO_MODULE_LOCK;WIL_SUPPRESS_EXCEPTIONS;WIL_USE_STL=1;NOGDICAPMASKS;NOICONS;NOATOM;NOCLIPBOARD;NODRAWTEXT;NOMEMMGR;NOMETAFILE;NOMINMAX;NOOPENFILE;NOSCROLL;NOSERVICE;NOSOUND;NOTEXTMETRIC;NOCOMM;NOKANJI;NOHELP;NOPROFILER;NODEFERWINDOWPOS;NOMCX;NO_SHLWAPI_PATH;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(CommitId)'!=''">MP_COMMIT_ID=$(CommitId);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(MajorVersion)'!='' And '$(MinorVersion)'!='' And '$(PatchVersion)'!='' And '$(VersionTag)'!=''">MP_MAJOR_VERSION=$(MajorVersion);MP_MINOR_VERSION=$(MinorVersion);MP_PATCH_VERSION=$(PatchVersion);MP_VERSION_TAG=$(VersionTag);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(DebugBorder)'=='true'">MP_DEBUG_BORDER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(DebugInfoOnOverlay)'=='true'">MP_DEBUG_INFO_ON_OVERLAY;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(UseCompSwapchain)'=='true'">MP_USE_COMPSWAPCHAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(CommitId)' != ''">MP_COMMIT_ID=$(CommitId);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(MajorVersion)' != '' And '$(MinorVersion)' != '' And '$(PatchVersion)' != ''">MP_MAJOR_VERSION=$(MajorVersion);MP_MINOR_VERSION=$(MinorVersion);MP_PATCH_VERSION=$(PatchVersion);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(VersionTag)' != ''">MP_VERSION_TAG=$(VersionTag);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(DebugBorder)">MP_DEBUG_BORDER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(DebugInfoOnOverlay)">MP_DEBUG_INFO_ON_OVERLAY;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(UseCompSwapchain)">MP_USE_COMPSWAPCHAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<!-- /await:strict: 禁用协程的非标准语言扩展 -->
<AdditionalOptions Condition="!$(UseClangCL)">/await:strict %(AdditionalOptions)</AdditionalOptions>
<!-- -fstrict-vtable-pointers: 缓存虚表指针,这要求不能通过非法手段改变对象的动态类型 -->
<!-- -funsafe-math-optimizations: 以降低精度为代价提高浮点运算速度 -->
<!-- -fno-math-errno: 浮点操作不设置 errno这使一些数学函数可以内联 -->
<AdditionalOptions Condition="$(UseClangCL)">/clang:-Wno-missing-designated-field-initializers /clang:-Wno-missing-field-initializers /clang:-fstrict-vtable-pointers /clang:-funsafe-math-optimizations /clang:-fno-math-errno %(AdditionalOptions)</AdditionalOptions>
<!-- -mcx16: 启用 CX16 指令Windows 从 8.1 开始要求 CPU 支持它 -->
<AdditionalOptions Condition="$(UseClangCL) And '$(Platform)' == 'x64'">/clang:-mcx16 %(AdditionalOptions)</AdditionalOptions>
<!-- -march=native: 针对当前硬件生成优化代码 -->
<AdditionalOptions Condition="$(UseClangCL) And $(UseNativeMicroArch)">/clang:-march=native %(AdditionalOptions)</AdditionalOptions>
<!-- 修复编译 Shared 中源文件找不到 pch.h 的问题 -->
<AdditionalIncludeDirectories Condition="$(UseClangCL)">.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ItemDefinitionGroup Condition="'$(Configuration)' == 'Debug'">
<ClCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ItemDefinitionGroup Condition="'$(Configuration)' == 'Release'">
<ClCompile>
<!-- Release 下不允许编译警告 -->
<TreatWarningAsError>true</TreatWarningAsError>
@ -40,6 +50,12 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<!-- /Gw: 链接时删除未使用和重复的数据,可以减小二进制文件体积 -->
<!-- /Zc:checkGwOdr: 防止 /Gw 导致某些 ODR 违规被忽略 -->
<AdditionalOptions>/Gw %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="!$(UseClangCL)">/Zc:checkGwOdr %(AdditionalOptions)</AdditionalOptions>
<!-- clang-cl 不支持 /LTCG应使用 LTO -->
<AdditionalOptions Condition="$(UseClangCL)">/clang:-flto %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
@ -49,13 +65,13 @@
</ItemDefinitionGroup>
<!-- 所有项目共享的头文件 -->
<Import Project="$(MSBuildThisFileDirectory)Shared\Shared.vcxitems" Label="Shared" />
<Import Project="$(MSBuildThisFileDirectory)\Shared\Shared.vcxitems" Label="Shared" />
<!-- Conan 依赖 -->
<Import Project="$(SolutionDir)obj\$(Platform)\$(Configuration)\_ConanDeps\$(MSBuildProjectName)\conandeps.props" Condition="Exists('$(SolutionDir)obj\$(Platform)\$(Configuration)\_ConanDeps\$(MSBuildProjectName)\conandeps.props')" />
<Import Project="$(SolutionDir)\obj\$(Platform)\$(Configuration)\_ConanDeps\$(MSBuildProjectName)\conandeps.props" Condition="Exists('$(SolutionDir)\obj\$(Platform)\$(Configuration)\_ConanDeps\$(MSBuildProjectName)\conandeps.props')" />
<!-- HybridCRT -->
<Import Project="$(MSBuildThisFileDirectory)HybridCRT.props" />
<Import Project="$(MSBuildThisFileDirectory)\HybridCRT.props" />
<!-- _CopyFilesMarkedCopyLocal 有一个 bug即使没有复制任何文件也会更改 @(FileWrites),经常导致 -->
<!-- up-to-date 检查失败。这个任务用于在 _CopyFilesMarkedCopyLocal 执行后修正 @(FileWrites)。 -->

View file

@ -5,26 +5,29 @@
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
</ItemGroup>
<!-- 编译选项 -->
<Import Project="$(MSBuildThisFileDirectory)\BuildOptions.props" />
<PropertyGroup>
<IsDebug>$(Configuration.StartsWith('Debug'))</IsDebug>
<IsPackaged>$(Configuration.EndsWith('Packaged'))</IsPackaged>
<DefaultLanguage>en-US</DefaultLanguage>
</PropertyGroup>
<!-- 编译选项 -->
<Import Project="$(MSBuildThisFileDirectory)BuildOptions.props" />
<PropertyGroup Label="Configuration">
<PlatformToolset Condition="$(UseClangCL)">ClangCL</PlatformToolset>
<PlatformToolset Condition="!$(UseClangCL)">v143</PlatformToolset>
</PropertyGroup>
</Project>

View file

@ -1,18 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\Common.Pre.props" />
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{62503530-b84b-4cc2-80b6-3f89618172b7}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)obj\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
<IntDir>$(SolutionDir)\obj\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
<OutDir>$(SolutionDir)\bin\$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="..\Common.Pre.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>Utility</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
@ -20,7 +19,7 @@
</ImportGroup>
<ItemDefinitionGroup>
<CopyFileToFolders>
<DestinationFolders>$(OutDir)effects</DestinationFolders>
<DestinationFolders>$(OutDir)\effects</DestinationFolders>
<DestinationFileName>%(RelativeDir)%(Filename)%(Extension)</DestinationFileName>
</CopyFileToFolders>
</ItemDefinitionGroup>

View file

@ -8,14 +8,15 @@
namespace Magpie {
static winrt::com_ptr<IPresentationFactory> CreatePresentationFactory(ID3D11Device* d3dDevice) noexcept {
static const auto createPresentationFactory = []() {
HMODULE hDcomp = GetModuleHandle(L"dcomp.dll");
assert(hDcomp);
return (decltype(::CreatePresentationFactory)*)GetProcAddress(
hDcomp, "CreatePresentationFactory");
}();
winrt::com_ptr<IPresentationFactory> result;
static const auto createPresentationFactory =
Win32Helper::LoadSystemFunction<decltype(::CreatePresentationFactory)>(
L"dcomp.dll", "CreatePresentationFactory");
if (!createPresentationFactory) {
return result;
}
HRESULT hr = createPresentationFactory(d3dDevice, IID_PPV_ARGS(&result));
if (FAILED(hr)) {
Logger::Get().ComError("CreatePresentationFactory 失败", hr);

View file

@ -200,11 +200,8 @@ void CursorManager::_ShowSystemCursor(bool show, bool onDestory) {
return;
}
static void (WINAPI* const showSystemCursor)(BOOL bShow) = []()->void(WINAPI*)(BOOL) {
HMODULE hUser32 = GetModuleHandle(L"user32.dll");
assert(hUser32);
return (void(WINAPI*)(BOOL))GetProcAddress(hUser32, "ShowSystemCursor");
}();
static const auto showSystemCursor =
Win32Helper::LoadSystemFunction<void WINAPI(BOOL)>(L"user32.dll", "ShowSystemCursor");
if (showSystemCursor) {
showSystemCursor((BOOL)show);
@ -1114,7 +1111,6 @@ void CursorManager::_StartCapture(POINT& cursorPos) noexcept {
}
const Renderer& renderer = ScalingWindow::Get().Renderer();
const RECT& srcRect = renderer.SrcRect();
const RECT& destRect = renderer.DestRect();
// 在以下情况下进入捕获状态:
@ -1127,9 +1123,6 @@ void CursorManager::_StartCapture(POINT& cursorPos) noexcept {
//
// 在有黑边的情况下自动将光标调整到画面内
SIZE srcFrameSize = Win32Helper::GetSizeOfRect(srcRect);
SIZE outputSize = Win32Helper::GetSizeOfRect(destRect);
_AdjustCursorSpeed();
// 移动光标位置,应跳过黑边

View file

@ -52,7 +52,7 @@ public:
}
void IsCursorCapturedOnOverlay(bool value) noexcept;
const int16_t SrcHitTest() const noexcept {
int16_t SrcHitTest() const noexcept {
return _lastCompletedHitTestResult;
}

View file

@ -1,5 +1,5 @@
#include "pch.h"
#include "DDShelper.h"
#include "DDSHelper.h"
#include "DDS.h"
#include "Logger.h"

View file

@ -4,6 +4,7 @@
#include "ScalingWindow.h"
#include "DirectXHelper.h"
#include "DeviceResources.h"
#include "Win32Helper.h"
namespace Magpie {
@ -16,18 +17,18 @@ using DwmGetDxSharedSurfaceFunc = BOOL(
ULONGLONG* pWin32KUpdateId
);
static DwmGetDxSharedSurfaceFunc* dwmGetDxSharedSurface = nullptr;
static DwmGetDxSharedSurfaceFunc* DwmGetDxSharedSurface = nullptr;
bool DwmSharedSurfaceFrameSource::_Initialize() noexcept {
if (!dwmGetDxSharedSurface) {
HMODULE hUser32 = GetModuleHandle(L"user32.dll");
assert(hUser32);
dwmGetDxSharedSurface = (DwmGetDxSharedSurfaceFunc*)GetProcAddress(hUser32, "DwmGetDxSharedSurface");
[[maybe_unused]] static Ignore _ = [] {
DwmGetDxSharedSurface = Win32Helper::LoadSystemFunction<DwmGetDxSharedSurfaceFunc>(
L"user32.dll", "DwmGetDxSharedSurface");
return Ignore();
}();
if (!dwmGetDxSharedSurface) {
Logger::Get().Win32Error("获取函数 DwmGetDxSharedSurface 地址失败");
return false;
}
if (!DwmGetDxSharedSurface) {
Logger::Get().Win32Error("获取函数 DwmGetDxSharedSurface 地址失败");
return false;
}
const SrcTracker& srcTracker = ScalingWindow::Get().SrcTracker();
@ -85,7 +86,7 @@ bool DwmSharedSurfaceFrameSource::_Initialize() noexcept {
FrameSourceState DwmSharedSurfaceFrameSource::_Update() noexcept {
HANDLE sharedTextureHandle = NULL;
if (!dwmGetDxSharedSurface(ScalingWindow::Get().SrcTracker().Handle(),
if (!DwmGetDxSharedSurface(ScalingWindow::Get().SrcTracker().Handle(),
&sharedTextureHandle, nullptr, nullptr, nullptr, nullptr)
|| !sharedTextureHandle
) {

View file

@ -255,7 +255,7 @@ void EffectCacheManager::Save(
int i = 6;
for (; i < 22; ++i) {
const wchar_t c = fileName[effectNameLen + i];
if (!(c >= L'0' && c <= L'9' || c >= L'a' && c <= L'f')) {
if (!((c >= L'0' && c <= L'9') || (c >= L'a' && c <= L'f'))) {
break;
}
}
@ -271,7 +271,7 @@ void EffectCacheManager::Save(
int i = 1;
for (; i < 18; ++i) {
const wchar_t c = fileName[effectNameLen + i];
if (!(c >= L'0' && c <= L'9' || c >= L'a' && c <= L'f')) {
if (!((c >= L'0' && c <= L'9') || (c >= L'a' && c <= L'f'))) {
break;
}
}

View file

@ -1160,21 +1160,23 @@ static uint32_t GeneratePassSource(
////////////////////////////////////////////////////////////////////////////////////////////////////////
// SRV
for (int i = 0; i < passDesc.inputs.size(); ++i) {
for (uint32_t i = 0, end = (uint32_t)passDesc.inputs.size(); i < end; ++i) {
auto& texDesc = desc.textures[passDesc.inputs[i]];
result.append(fmt::format("Texture2D<{}> {} : register(t{});\n", EffectHelper::FORMAT_DESCS[(uint32_t)texDesc.format].srvTexelType, texDesc.name, i));
result.append(fmt::format("Texture2D<{}> {} : register(t{});\n",
EffectHelper::FORMAT_DESCS[(uint32_t)texDesc.format].srvTexelType, texDesc.name, i));
}
// UAV
for (int i = 0; i < passDesc.outputs.size(); ++i) {
for (uint32_t i = 0, end = (uint32_t)passDesc.outputs.size(); i < end; ++i) {
auto& texDesc = desc.textures[passDesc.outputs[i]];
result.append(fmt::format("RWTexture2D<{}> {} : register(u{});\n", EffectHelper::FORMAT_DESCS[(uint32_t)texDesc.format].uavTexelType, texDesc.name, i));
result.append(fmt::format("RWTexture2D<{}> {} : register(u{});\n",
EffectHelper::FORMAT_DESCS[(uint32_t)texDesc.format].uavTexelType, texDesc.name, i));
}
if (!desc.samplers.empty()) {
// 采样器
for (int i = 0; i < desc.samplers.size(); ++i) {
for (uint32_t i = 0, end = (uint32_t)desc.samplers.size(); i < end; ++i) {
result.append(fmt::format("SamplerState {} : register(s{});\n", desc.samplers[i].name, i));
}
}
@ -1344,7 +1346,9 @@ MF4 MulAdd(MF4 x, MF4x4 y, MF4 a) {
//
////////////////////////////////////////////////////////////////////////////////////////////////////////
if (passDesc.flags & EffectPassFlags::PSStyle) {
if (passDesc.outputs.size() <= 1) {
const uint32_t outputCount = (uint32_t)passDesc.outputs.size();
if (outputCount <= 1u) {
std::string outputSize;
std::string outputPt;
if (passIdx == desc.passes.size()) {
@ -1397,7 +1401,7 @@ void __M(uint3 tid : SV_GroupThreadID, uint3 gid : SV_GroupID) {{
float2 pos = (gxy + 0.5f) * __pass{0}OutputPt;
float2 step = 8 * __pass{0}OutputPt;
)", passIdx));
for (int i = 0; i < passDesc.outputs.size(); ++i) {
for (uint32_t i = 0; i < outputCount; ++i) {
auto& texDesc = desc.textures[passDesc.outputs[i]];
result.append(fmt::format("\t{} c{};\n",
EffectHelper::FORMAT_DESCS[(uint32_t)texDesc.format].srvTexelType, i));
@ -1405,12 +1409,13 @@ void __M(uint3 tid : SV_GroupThreadID, uint3 gid : SV_GroupID) {{
std::string callPass = fmt::format("\tPass{}(pos, ", passIdx);
for (int i = 0; i < passDesc.outputs.size() - 1; ++i) {
for (uint32_t i = 0, end = outputCount - 1; i < end; ++i) {
callPass.append(fmt::format("c{}, ", i));
}
callPass.append(fmt::format("c{});\n", passDesc.outputs.size() - 1));
for (int i = 0; i < passDesc.outputs.size(); ++i) {
callPass.append(fmt::format("\t\t\t{}[gxy] = c{};\n", desc.textures[passDesc.outputs[i]].name, i));
callPass.append(fmt::format("c{});\n", outputCount - 1));
for (uint32_t i = 0; i < outputCount; ++i) {
callPass.append(fmt::format("\t\t\t{}[gxy] = c{};\n",
desc.textures[passDesc.outputs[i]].name, i));
}
result.append(fmt::format(R"({0}

View file

@ -84,7 +84,7 @@ void ImGuiBackend::RenderDrawData(const ImDrawData& drawData, POINT viewportOffs
_vertexBufferSize = drawData.TotalVtxCount + 5000;
D3D11_BUFFER_DESC desc{
.ByteWidth = _vertexBufferSize * sizeof(ImDrawVert),
.ByteWidth = UINT(_vertexBufferSize * sizeof(ImDrawVert)),
.Usage = D3D11_USAGE_DYNAMIC,
.BindFlags = D3D11_BIND_VERTEX_BUFFER,
.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE
@ -99,7 +99,7 @@ void ImGuiBackend::RenderDrawData(const ImDrawData& drawData, POINT viewportOffs
_indexBufferSize = drawData.TotalIdxCount + 10000;
D3D11_BUFFER_DESC desc{
.ByteWidth = _indexBufferSize * sizeof(ImDrawIdx),
.ByteWidth = UINT(_indexBufferSize * sizeof(ImDrawIdx)),
.Usage = D3D11_USAGE_DYNAMIC,
.BindFlags = D3D11_BIND_INDEX_BUFFER,
.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE

View file

@ -12,14 +12,13 @@
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{0e5205ae-dfa9-4cb8-b662-e43cd6512e2a}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
<IntDir>$(SolutionDir)obj\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
<GeneratedFilesDir>$(IntDir)Generated Files\</GeneratedFilesDir>
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\obj\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
<OutDir>$(SolutionDir)\bin\$(Platform)\$(Configuration)\</OutDir>
<GeneratedFilesDir>$(IntDir)\Generated Files\</GeneratedFilesDir>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@ -29,12 +28,11 @@
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\Common.Post.props" />
<Import Project="$(SolutionDir)obj\$(Platform)\$(Configuration)\_ConanDeps\Magpie\conandeps.props" Condition="Exists('$(SolutionDir)obj\$(Platform)\$(Configuration)\_ConanDeps\Magpie\conandeps.props')" />
<Import Project="$(SolutionDir)\obj\$(Platform)\$(Configuration)\_ConanDeps\Magpie\conandeps.props" Condition="Exists('$(SolutionDir)\obj\$(Platform)\$(Configuration)\_ConanDeps\Magpie\conandeps.props')" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<FloatingPointModel>Fast</FloatingPointModel>
<AdditionalIncludeDirectories>include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<FxCompile>
@ -42,7 +40,7 @@
<AllResourcesBound>true</AllResourcesBound>
<TreatWarningAsError>true</TreatWarningAsError>
<VariableName>%(Filename)</VariableName>
<HeaderFileOutput>$(GeneratedFilesDir)shaders\%(Filename).h</HeaderFileOutput>
<HeaderFileOutput>$(GeneratedFilesDir)\shaders\%(Filename).h</HeaderFileOutput>
<ObjectFileOutput />
</FxCompile>
</ItemDefinitionGroup>

View file

@ -64,12 +64,6 @@
<ClInclude Include="include\WindowHelper.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="include\StrHelper.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="include\Version.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="include\Win32Helper.h">
<Filter>Include</Filter>
</ClInclude>
@ -176,13 +170,9 @@
<Filter>Capture</Filter>
</ClCompile>
<ClCompile Include="ScalingOptions.cpp" />
<ClCompile Include="Version.cpp" />
<ClCompile Include="Win32Helper.cpp">
<Filter>Helpers</Filter>
</ClCompile>
<ClCompile Include="StrHelper.cpp">
<Filter>Helpers</Filter>
</ClCompile>
<ClCompile Include="BackendDescriptorStore.cpp">
<Filter>Render</Filter>
</ClCompile>

View file

@ -33,15 +33,13 @@ bool PresenterBase::Initialize(HWND hwndAttach, const DeviceResources& deviceRes
void PresenterBase::_WaitForDwmComposition() noexcept {
// Win11 可以使用准确的 DCompositionWaitForCompositorClock
if (Win32Helper::GetOSVersion().IsWin11()) {
static const auto dCompositionWaitForCompositorClock = []() {
HMODULE hDcomp = GetModuleHandle(L"dcomp.dll");
assert(hDcomp);
return (decltype(::DCompositionWaitForCompositorClock)*)GetProcAddress(
hDcomp, "DCompositionWaitForCompositorClock");
}();
dCompositionWaitForCompositorClock(0, nullptr, INFINITE);
return;
static const auto dCompositionWaitForCompositorClock =
Win32Helper::LoadSystemFunction<decltype(DCompositionWaitForCompositorClock)>(
L"dcomp.dll", "DCompositionWaitForCompositorClock");
if (dCompositionWaitForCompositorClock) {
dCompositionWaitForCompositorClock(0, nullptr, INFINITE);
return;
}
}
LARGE_INTEGER qpf;

View file

@ -865,7 +865,7 @@ HANDLE Renderer::_InitBackend() noexcept {
// 某些捕获方式不会限制捕获帧率,因此将捕获帧率限制为屏幕刷新率
const HWND hwndSrc = ScalingWindow::Get().SrcTracker().Handle();
if (HMONITOR hMon = MonitorFromWindow(hwndSrc, MONITOR_DEFAULTTONEAREST)) {
MONITORINFOEX mi{ sizeof(MONITORINFOEX) };
MONITORINFOEX mi{ { sizeof(MONITORINFOEX) } };
GetMonitorInfo(hMon, &mi);
DEVMODE dm{ .dmSize = sizeof(DEVMODE) };

View file

@ -21,7 +21,7 @@ static UINT WM_MAGPIE_SCALINGCHANGED;
static constexpr int WINDOWED_MODE_MIN_SPACE_AROUND = 2 * 50;
static void InitMessage() noexcept {
static Ignore _ = []() {
[[maybe_unused]] static Ignore _ = []() {
WM_MAGPIE_SCALINGCHANGED =
RegisterWindowMessage(CommonSharedConstants::WM_MAGPIE_SCALINGCHANGED);
@ -101,7 +101,7 @@ ScalingError ScalingWindow::Create(HWND hwndSrc, ScalingOptions options) noexcep
Win32Helper::GetWindowPath(hwndSrc), Win32Helper::GetWindowClassName(hwndSrc)).c_str());
#endif
static Ignore _ = []() {
[[maybe_unused]] static Ignore _ = []() {
WNDCLASSEXW wcex{
.cbSize = sizeof(wcex),
.lpfnWndProc = _WndProc,
@ -1494,7 +1494,7 @@ LRESULT ScalingWindow::_BorderHelperWndProc(HWND hWnd, UINT msg, WPARAM wParam,
}
void ScalingWindow::_CreateBorderHelperWindows() noexcept {
static Ignore _ = [] {
[[maybe_unused]] static Ignore _ = [] {
WNDCLASSEXW wcex{
.cbSize = sizeof(wcex),
.lpfnWndProc = _BorderHelperWndProc,
@ -1677,7 +1677,7 @@ void ScalingWindow::_UpdateTouchHoleWindows(bool onInit) noexcept {
const RECT srcTouchRect = _CalcSrcTouchRect();
_UpdateTouchProps(srcTouchRect);
static Ignore _ = [] {
[[maybe_unused]] static Ignore _ = [] {
WNDCLASSEXW wcex{
.cbSize = sizeof(wcex),
.lpfnWndProc = BkgWndProc,

View file

@ -10,7 +10,7 @@ class CursorManager;
class ScalingWindow : public WindowBaseT<ScalingWindow> {
using base_type = WindowBaseT<ScalingWindow>;
friend class base_type;
friend base_type;
public:
static ScalingWindow& Get() noexcept {

View file

@ -371,8 +371,9 @@ static HWND FindClientWindowOfUWP(HWND hwndSrc, const wchar_t* clientWndClassNam
}
// 如果有多个匹配的子窗口,取最大的(一般不会出现)
int maxSize = 0, maxIdx = 0;
for (int i = 0; i < data.childWindows.size(); ++i) {
int maxSize = 0;
uint32_t maxIdx = 0;
for (uint32_t i = 0, end = (uint32_t)data.childWindows.size(); i < end; ++i) {
RECT rect;
if (!GetClientRect(data.childWindows[i], &rect)) {
continue;

View file

@ -1,6 +1,5 @@
#include "pch.h"
#include "Win32Helper.h"
#include "Logger.h"
#include "StrHelper.h"
#include <io.h>
#include <Psapi.h>
@ -39,32 +38,33 @@ std::wstring Win32Helper::GetWindowTitle(HWND hWnd) noexcept {
}
wil::unique_process_handle Win32Helper::GetWindowProcessHandle(HWND hWnd) noexcept {
wil::unique_process_handle hProc;
wil::unique_process_handle result;
if (DWORD dwProcId = 0; GetWindowThreadProcessId(hWnd, &dwProcId)) {
hProc.reset(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcId));
if (!hProc) {
result.reset(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcId));
if (result) {
return result;
} else {
Logger::Get().Win32Error("OpenProcess 失败");
}
} else {
Logger::Get().Win32Error("GetWindowThreadProcessId 失败");
}
if (!hProc) {
// 在某些窗口上 OpenProcess 会失败(如暗黑 2尝试使用 GetProcessHandleFromHwnd
static const auto getProcessHandleFromHwnd = (HANDLE(WINAPI*)(HWND))GetProcAddress(
LoadLibraryEx(L"Oleacc.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32),
"GetProcessHandleFromHwnd"
);
if (getProcessHandleFromHwnd) {
hProc.reset(getProcessHandleFromHwnd(hWnd));
if (!hProc) {
Logger::Get().Win32Error("GetProcessHandleFromHwnd 失败");
}
}
// 在某些窗口上 OpenProcess 会失败(如暗黑 2尝试使用 GetProcessHandleFromHwnd
static const auto getProcessHandleFromHwnd =
Win32Helper::LoadSystemFunction<HANDLE WINAPI(HWND)>(L"Oleacc.dll", "GetProcessHandleFromHwnd");
if (!getProcessHandleFromHwnd) {
return result;
}
return hProc;
result.reset(getProcessHandleFromHwnd(hWnd));
if (!result) {
Logger::Get().Win32Error("GetProcessHandleFromHwnd 失败");
return result;
}
return result;
}
std::wstring Win32Helper::GetWindowPath(HWND hWnd) noexcept {
@ -199,7 +199,7 @@ int16_t Win32Helper::AdvancedWindowHitTest(HWND hWnd, POINT ptScreen, UINT timeo
DWORD_PTR area = HTNOWHERE;
SendMessageTimeout(hwndChild, WM_NCHITTEST, 0, MAKELPARAM(ptScreen.x, ptScreen.y),
SMTO_NORMAL, timeout, &area);
if (area != HTTRANSPARENT) {
if ((int)area != HTTRANSPARENT) {
hwndCur = hwndChild;
hittest = (int16_t)area;
continue;
@ -258,7 +258,7 @@ int16_t Win32Helper::AdvancedWindowHitTest(HWND hWnd, POINT ptScreen, UINT timeo
DWORD_PTR area = HTNOWHERE;
SendMessageTimeout(hWnd, WM_NCHITTEST, 0,
MAKELPARAM(data->ptScreen.x, data->ptScreen.y), SMTO_NORMAL, data->timeout, &area);
if (area == HTTRANSPARENT) {
if ((int)area == HTTRANSPARENT) {
return TRUE;
}
@ -422,21 +422,17 @@ bool Win32Helper::CreateDir(const std::wstring& path, bool recursive) noexcept {
}
const Win32Helper::OSVersion& Win32Helper::GetOSVersion() noexcept {
static OSVersion version = []() -> OSVersion {
HMODULE hNtDll = GetModuleHandle(L"ntdll.dll");
assert(hNtDll);
auto rtlGetVersion = (LONG(WINAPI*)(PRTL_OSVERSIONINFOW))GetProcAddress(hNtDll, "RtlGetVersion");
static OSVersion version = [] {
const auto rtlGetVersion =
LoadSystemFunction<LONG WINAPI(PRTL_OSVERSIONINFOW)>(L"ntdll.dll", "RtlGetVersion");
if (!rtlGetVersion) {
Logger::Get().Win32Error("获取 RtlGetVersion 地址失败");
assert(false);
return {};
return OSVersion();
}
RTL_OSVERSIONINFOW versionInfo{ .dwOSVersionInfoSize = sizeof(versionInfo) };
rtlGetVersion(&versionInfo);
return { versionInfo.dwMajorVersion, versionInfo.dwMinorVersion, versionInfo.dwBuildNumber };
return OSVersion(versionInfo.dwMajorVersion, versionInfo.dwMinorVersion, versionInfo.dwBuildNumber);
}();
return version;

View file

@ -1,5 +1,7 @@
#pragma once
#include "Version.h"
#include "Logger.h"
#include "StrHelper.h"
namespace Magpie {
@ -175,6 +177,39 @@ struct Win32Helper {
static bool OpenFolderAndSelectFile(const wchar_t* fileName) noexcept;
static const std::filesystem::path& GetExePath() noexcept;
template<typename T, std::enable_if_t<std::is_function_v<T>, int> = 0>
static T* LoadSystemFunction(const wchar_t* dllName, const char* funcName) noexcept {
assert(dllName && funcName);
HMODULE hMod = GetModuleHandle(dllName);
if (!hMod) {
hMod = LoadLibraryEx(dllName, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!hMod) {
Logger::Get().Win32Error(fmt::format("加载 {} 失败",
StrHelper::UTF16ToUTF8(dllName)));
return nullptr;
}
}
const FARPROC address = GetProcAddress(hMod, funcName);
if (!address) {
const uintptr_t ordinal = reinterpret_cast<uintptr_t>(funcName);
// 小于 0xFFFF 则为序号
if (ordinal <= 0xFFFFu) {
Logger::Get().Win32Error(fmt::format("加载 {}!{} 失败",
StrHelper::UTF16ToUTF8(dllName), ordinal));
} else {
Logger::Get().Win32Error(fmt::format("加载 {}!{} 失败",
StrHelper::UTF16ToUTF8(dllName), funcName));
}
return nullptr;
}
// 先转成 void* 以避免警告
return reinterpret_cast<T*>(reinterpret_cast<void*>(address));
}
};
}

View file

@ -61,7 +61,7 @@ hstring AboutViewModel::Version() const noexcept {
resourceLoader.GetString(L"About_Version_Version"),
#ifdef MP_VERSION_TAG
L" ",
WIDEN(STRING(MP_VERSION_TAG)) + 1,
&WIDEN(STRING(MP_VERSION_TAG))[1],
#else
L" dev",
#endif

View file

@ -98,7 +98,7 @@ App& App::Get() {
}
App::App() {
UnhandledException([this](IInspectable const&, UnhandledExceptionEventArgs const& e) {
UnhandledException([](IInspectable const&, UnhandledExceptionEventArgs const& e) {
Logger::Get().ComCritical("未处理的异常", e.Exception().value);
if (IsDebuggerPresent()) {

View file

@ -1,9 +1,9 @@
#pragma once
#include "App.g.h"
#include <winrt/Windows.UI.Xaml.Hosting.h>
#include <winrt/Windows.Globalization.NumberFormatting.h>
#include "AppSettings.h"
#include "Event.h"
#include <winrt/Windows.Globalization.NumberFormatting.h>
#include <winrt/Windows.UI.Xaml.Hosting.h>
namespace Magpie {
class MainWindow;

View file

@ -32,6 +32,7 @@ namespace Magpie {
#include "CandidateWindowItem.idl"
#include "NewProfileViewModel.idl"
#include "AboutViewModel.idl"
#include "ToastPage.idl"
#include "RootPage.idl"
#include "AboutPage.idl"
#include "HomePage.idl"

View file

@ -1,22 +1,22 @@
#include "pch.h"
#include "App.h"
#include "AppSettings.h"
#include "AutoStartHelper.h"
#include "CommonSharedConstants.h"
#include "JsonHelper.h"
#include "LocalizationService.h"
#include "Logger.h"
#include "MainWindow.h"
#include "Profile.h"
#include "resource.h"
#include "ScalingMode.h"
#include "ScalingModesService.h"
#include "ShortcutHelper.h"
#include "StrHelper.h"
#include "Win32Helper.h"
#include "Logger.h"
#include "ShortcutHelper.h"
#include "Profile.h"
#include "CommonSharedConstants.h"
#include "AutoStartHelper.h"
#include "ScalingModesService.h"
#include "JsonHelper.h"
#include "ScalingMode.h"
#include "LocalizationService.h"
#include "resource.h"
#include "App.h"
#include "MainWindow.h"
#include <rapidjson/prettywriter.h>
#include <ShlObj.h>
#include <ShellScalingApi.h>
#include <ShlObj.h>
using namespace winrt;
using namespace winrt::Magpie;
@ -950,7 +950,7 @@ bool AppSettings::_LoadProfile(
}
JsonHelper::ReadInt(profileObj, "scalingMode", profile.scalingMode);
if (profile.scalingMode < -1 || profile.scalingMode >= _scalingModes.size()) {
if (profile.scalingMode < -1 || profile.scalingMode >= (int)_scalingModes.size()) {
profile.scalingMode = -1;
}

View file

@ -1,18 +1,18 @@
#include "pch.h"
#include "AppXReader.h"
#include "Win32Helper.h"
#include "StrHelper.h"
#include "Logger.h"
#include "StrHelper.h"
#include "Win32Helper.h"
#include <appmodel.h>
#include <propkey.h>
#include <regex>
#include <wincodec.h>
#include <parallel_hashmap/phmap.h>
#include <AppxPackaging.h>
#include <parallel_hashmap/phmap.h>
#include <propkey.h>
#include <propsys.h>
#include <winrt/Windows.Graphics.Imaging.h>
#include <Shlwapi.h>
#include <regex>
#include <shellapi.h>
#include <Shlwapi.h>
#include <wincodec.h>
#include <winrt/Windows.Graphics.Imaging.h>
using namespace winrt;
using namespace Windows::Graphics::Imaging;

View file

@ -3,10 +3,10 @@
#include "Logger.h"
#include "StrHelper.h"
#include "Win32Helper.h"
#include <Lmcons.h>
#include <propkey.h>
#include <ShlObj.h>
#include <taskschd.h>
#include <Lmcons.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//

View file

@ -41,7 +41,7 @@ private:
struct ScalingModeFloatParameter : ScalingModeFloatParameterT<ScalingModeFloatParameter>,
wil::notify_property_changed_base<ScalingModeFloatParameter> {
ScalingModeFloatParameter(uint32_t index, const hstring& label, float initValue, float minimum, float maximum, float step)
: _index(index), _label(label), _value(initValue), _minimum(minimum), _maximum(maximum), _step(step) {
: _index(index), _label(label), _minimum(minimum), _maximum(maximum), _step(step), _value(initValue) {
}
uint32_t Index() const noexcept {

View file

@ -326,7 +326,7 @@ int HomeViewModel::MinFrameRateIndex() const noexcept {
}
void HomeViewModel::MinFrameRateIndex(int value) {
if (value < 0 || value >= MIN_FRAME_RATE_OPTIONS.size()) {
if (value < 0 || value >= (int)MIN_FRAME_RATE_OPTIONS.size()) {
return;
}

View file

@ -20,9 +20,9 @@
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)' == ''">10.0.26100.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.26100.0</WindowsTargetPlatformMinVersion>
<IntDir>$(SolutionDir)obj\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\</OutDir>
<GeneratedFilesDir>$(IntDir)Generated Files\</GeneratedFilesDir>
<IntDir>$(SolutionDir)\obj\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
<OutDir>$(SolutionDir)\bin\$(Platform)\$(Configuration)\</OutDir>
<GeneratedFilesDir>$(IntDir)\Generated Files\</GeneratedFilesDir>
<AppxBundlePlatforms>x64|arm64</AppxBundlePlatforms>
<DesktopCompatible>true</DesktopCompatible>
<!-- 将 xbf 文件打包进 pri -->
@ -33,6 +33,8 @@
<GenerateLibraryLayout>true</GenerateLibraryLayout>
<!-- 直接生成 resources.pri使用 ComputeInputPriFiles 合并引用的 pri -->
<ProjectPriFileName>resources.pri</ProjectPriFileName>
<!-- 跳过 CreateWinMD这一步似乎是多余的而且 clang-cl 不支持生成 winmd -->
<GenerateBuildCompilePassWinMD>false</GenerateBuildCompilePassWinMD>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
@ -41,6 +43,27 @@
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup Condition="$(UseClangCL)">
<!-- 来自 $(VCTargetsPath)\Microsoft.Cpp.ClangCl.Common.props -->
<CLToolExe>clang-cl.exe</CLToolExe>
<LinkToolExe>lld-link.exe</LinkToolExe>
<LibToolExe>llvm-lib.exe</LibToolExe>
<LLVMInstallDir Condition="'$(PreferredToolArchitecture)' == 'x64'">$(VsInstallRoot)\VC\Tools\Llvm\x64\</LLVMInstallDir>
<LLVMInstallDir Condition="'$(PreferredToolArchitecture)' == 'arm64'">$(VsInstallRoot)\VC\Tools\Llvm\ARM64\</LLVMInstallDir>
<LLVMInstallDir Condition="'$(LLVMInstallDir)' == ''">$(VsInstallRoot)\VC\Tools\Llvm\</LLVMInstallDir>
<ExecutablePath>$(LLVMInstallDir)\bin;$(ExecutablePath)</ExecutablePath>
<!-- Add Clang include path for IntelliSense -->
<IncludePath>$(LLVMInstallDir)\lib\clang\$(LLVMIncludeVersion)\include;$(IncludePath)</IncludePath>
<ExcludePath>$(LLVMInstallDir)\lib\clang\$(LLVMIncludeVersion)\include;$(ExcludePath)</ExcludePath>
<!-- ClangCl is not compatible with MSVC analysis, use clang-tidy as default -->
<EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>
<EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
<ClCompilerPath>$(ClangAnalysisToolsPath)\clang-cl.exe</ClCompilerPath>
<LlvmArchitectureSwitch Condition="'$(Platform)'=='x64'">--target=amd64-pc-windows-msvc</LlvmArchitectureSwitch>
<LlvmArchitectureSwitch Condition="'$(Platform)'=='ARM64'">--target=arm64-pc-windows-msvc</LlvmArchitectureSwitch>
<!-- clang-cl 不支持 /MP设置 MultiProcCL 属性可以并行运行多个 clang-cl 进程 -->
<MultiProcCL>true</MultiProcCL>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared" />
@ -60,6 +83,15 @@
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>..\Magpie.Core\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<ClCompile Condition="$(UseClangCL)">
<!-- 禁用 cppwinrt 生成的头文件中的编译警告 -->
<AdditionalOptions>/clang:-isystem /clang:"$(GeneratedFilesDir)\" $(LlvmArchitectureSwitch) %(AdditionalOptions)</AdditionalOptions>
<!-- clang-cl 不支持 /ZI而且 /Zi 和 /Z7 效果相同。 -->
<!-- Microsoft.Cpp.ClangCl.Common.target 始终使用 OldStyle (/Z7),我们和它保持一致。 -->
<DebugInformationFormat>OldStyle</DebugInformationFormat>
<!-- clang-cl 使用 MultiProcCL 属性实现并行编译 -->
<MultiProcessorCompilation>false</MultiProcessorCompilation>
</ClCompile>
<Link>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<SubSystem>Windows</SubSystem>
@ -67,6 +99,9 @@
<DelayLoadDLLs>d3dcompiler_47.dll;Magnification.dll;Imagehlp.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<!-- 删除 clang-cl 不支持的选项 -->
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.ClangCl.Exclusion.props" Condition="$(UseClangCL)" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.LldLink.Exclusion.props" Condition="$(UseClangCL)" />
<ItemGroup>
<ClInclude Include="AboutPage.h">
<DependentUpon>AboutPage.xaml</DependentUpon>
@ -456,10 +491,10 @@
<None Include="TextMenuFlyout.idl">
<SubType>Designer</SubType>
</None>
<Midl Include="ToastPage.idl">
<None Include="ToastPage.idl">
<DependentUpon>ToastPage.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
</None>
<None Include="SettingsExpanderCornerRadiusConverter.idl">
<SubType>Designer</SubType>
</None>
@ -651,9 +686,15 @@
<PRIResource Include="Resources.language-en-US.resw" />
<PRIResource Include="Resources.language-es.resw" />
<PRIResource Include="Resources.language-fr.resw" />
<None Include="Resources.language-hu.resw">
<FileType>Document</FileType>
</None>
<PRIResource Include="Resources.language-id.resw" />
<PRIResource Include="Resources.language-it.resw" />
<PRIResource Include="Resources.language-ja.resw" />
<None Include="Resources.language-ka.resw">
<FileType>Document</FileType>
</None>
<PRIResource Include="Resources.language-ko.resw" />
<PRIResource Include="Resources.language-pl.resw" />
<PRIResource Include="Resources.language-pt-BR.resw" />
@ -713,7 +754,7 @@
</ItemGroup>
</Target>
<PropertyGroup Condition="!$(IsPackaged)">
<_ManifestsDir>$(IntDir)Manifests\</_ManifestsDir>
<_ManifestsDir>$(IntDir)\Manifests\</_ManifestsDir>
</PropertyGroup>
<!-- 编译为非打包应用时向清单文件添加运行时使用到的 WinRT 组件 -->
<!-- Reg-free WinRT: https://blogs.windows.com/windowsdeveloper/2019/04/30/enhancing-non-packaged-desktop-apps-using-windows-runtime-components/ -->
@ -741,11 +782,34 @@
<Manifest Include="@(_UnpackagedWin32WinmdManifest)" />
</ItemGroup>
</Target>
<!-- 使用 clang-cl 编译 cppwinrt 生成的源文件时关闭警告-->
<Target Name="FixClangCLCppWinRT" BeforeTargets="ClCompile" Condition="$(UseClangCL)">
<ItemGroup>
<_XamlTypeInfoCpp Include="@(ClCompile)" Condition="'%(Extension)' == '.cpp' And ('%(Filename)' == 'XamlTypeInfo.Impl.g' Or '%(Filename)' == 'XamlTypeInfo.g')" />
<ClCompile Remove="@(_XamlTypeInfoCpp)" />
<ClCompile Include="@(_XamlTypeInfoCpp)">
<WarningLevel>TurnOffAllWarnings</WarningLevel>
</ClCompile>
</ItemGroup>
</Target>
<!-- lld-link 不支持 /WINMD 和 /WINMDFILE -->
<Target Name="FixClangCLLink" BeforeTargets="Link" Condition="$(UseClangCL)">
<PropertyGroup>
<_GenerateWindowsMetadata />
</PropertyGroup>
<ItemGroup>
<_NoWinMD Include="@(Link)" />
<Link Remove="@(_NoWinMD)" />
<Link Include="@(_NoWinMD)">
<WindowsMetadataFile />
</Link>
</ItemGroup>
</Target>
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.UI.Xaml.2.8.7\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\packages\Microsoft.UI.Xaml.2.8.7\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.250325.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.250325.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\..\packages\Microsoft.Web.WebView2.1.0.3296.44\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\packages\Microsoft.Web.WebView2.1.0.3296.44\build\native\Microsoft.Web.WebView2.targets')" />
<Import Project="..\..\packages\Microsoft.Web.WebView2.1.0.3351.48\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\packages\Microsoft.Web.WebView2.1.0.3351.48\build\native\Microsoft.Web.WebView2.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
@ -756,10 +820,10 @@
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.250325.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.250325.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Web.WebView2.1.0.3296.44\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Web.WebView2.1.0.3296.44\build\native\Microsoft.Web.WebView2.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Web.WebView2.1.0.3351.48\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Web.WebView2.1.0.3351.48\build\native\Microsoft.Web.WebView2.targets'))" />
</Target>
<!-- 防止生成的 winmd 被复制到输出文件夹 -->
<PropertyGroup Condition="!$(IsPackaged)">
<CppWinRTProjectWinMD>$(CppWinRTMergedDir)$(RootNamespace).winmd</CppWinRTProjectWinMD>
<CppWinRTProjectWinMD>$(CppWinRTMergedDir)\$(RootNamespace).winmd</CppWinRTProjectWinMD>
</PropertyGroup>
</Project>

View file

@ -285,6 +285,12 @@
<None Include="TextMenuFlyout.idl">
<Filter>Helpers</Filter>
</None>
<None Include="Resources.language-hu.resw">
<Filter>Strings</Filter>
</None>
<None Include="Resources.language-ka.resw">
<Filter>Strings</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Page Include="HomePage.xaml">

View file

@ -18,7 +18,7 @@ using namespace winrt::Magpie::implementation;
namespace Magpie {
bool MainWindow::Create() noexcept {
static Ignore _ = [] {
[[maybe_unused]] static Ignore _ = [] {
const HINSTANCE hInstance = wil::GetModuleInstanceHandle();
WNDCLASSEXW wcex{

View file

@ -94,10 +94,8 @@ static SmallVector<HWND> GetDesktopWindows() noexcept {
template<typename It>
static void SortCandidateWindows(It begin, It end) {
const std::collate<wchar_t>& col = std::use_facet<std::collate<wchar_t> >(std::locale());
// 根据用户的区域设置排序,对于中文为拼音顺序
std::sort(begin, end, [&col](com_ptr<CandidateWindowItem> const& l, com_ptr<CandidateWindowItem> const& r) {
std::sort(begin, end, [](com_ptr<CandidateWindowItem> const& l, com_ptr<CandidateWindowItem> const& r) {
hstring titleL = l->Title();
hstring titleR = r->Title();

View file

@ -108,6 +108,8 @@ void PageFrame::ScrollViewer_KeyDown(IInspectable const& sender, KeyRoutedEventA
case VirtualKey::Down:
scrollViewer.ChangeView(scrollViewer.HorizontalOffset(), scrollViewer.VerticalOffset() + 100, 1);
break;
default:
break;
}
}

View file

@ -264,7 +264,7 @@ hstring ScalingModeItem::Description() const noexcept {
result.append(L" > ");
}
if (const EffectInfo* effectInfo = EffectsService::Get().GetEffect(effect.name)) {
if (EffectsService::Get().GetEffect(effect.name) != nullptr) {
result += EffectHelper::GetDisplayName(effect.name);
} else {
ResourceLoader resourceLoader =

View file

@ -17,20 +17,20 @@ using namespace Windows::UI::Xaml::Input;
namespace winrt::Magpie::implementation {
static constexpr const wchar_t* CommonStates = L"CommonStates";
// static constexpr const wchar_t* CommonStates = L"CommonStates";
static constexpr const wchar_t* NormalState = L"Normal";
static constexpr const wchar_t* PointerOverState = L"PointerOver";
static constexpr const wchar_t* PressedState = L"Pressed";
static constexpr const wchar_t* DisabledState = L"Disabled";
static constexpr const wchar_t* ContentAlignmentStates = L"ContentAlignmentStates";
static constexpr const wchar_t* RightState = L"Right";
// static constexpr const wchar_t* RightState = L"Right";
static constexpr const wchar_t* RightWrappedState = L"RightWrapped";
static constexpr const wchar_t* RightWrappedNoIconState = L"RightWrappedNoIcon";
static constexpr const wchar_t* LeftState = L"Left";
// static constexpr const wchar_t* LeftState = L"Left";
static constexpr const wchar_t* VerticalState = L"Vertical";
static constexpr const wchar_t* ContentSpacingStates = L"ContentSpacingStates";
// static constexpr const wchar_t* ContentSpacingStates = L"ContentSpacingStates";
static constexpr const wchar_t* NoContentSpacingState = L"NoContentSpacing";
static constexpr const wchar_t* ContentSpacingState = L"ContentSpacing";
@ -71,21 +71,27 @@ void SettingsCard::RegisterDependencyProperties() {
L"Header",
xaml_typename<IInspectable>(),
xaml_typename<class_type>(),
PropertyMetadata(nullptr, &SettingsCard::_OnHeaderChanged)
PropertyMetadata(nullptr, [](DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsCard>(sender.as<class_type>())->_OnHeaderChanged();
})
);
_descriptionProperty = DependencyProperty::Register(
L"Description",
xaml_typename<IInspectable>(),
xaml_typename<class_type>(),
PropertyMetadata(nullptr, &SettingsCard::_OnDescriptionChanged)
PropertyMetadata(nullptr, [](DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsCard>(sender.as<class_type>())->_OnDescriptionChanged();
})
);
_headerIconProperty = DependencyProperty::Register(
L"HeaderIcon",
xaml_typename<IconElement>(),
xaml_typename<class_type>(),
PropertyMetadata(nullptr, &SettingsCard::_OnHeaderIconChanged)
PropertyMetadata(nullptr, [](DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsCard>(sender.as<class_type>())->_OnHeaderIconChanged();
})
);
_actionIconProperty = DependencyProperty::Register(
@ -106,7 +112,9 @@ void SettingsCard::RegisterDependencyProperties() {
L"IsClickEnabled",
xaml_typename<bool>(),
xaml_typename<class_type>(),
PropertyMetadata(box_value(false), &SettingsCard::_OnIsClickEnabledChanged)
PropertyMetadata(box_value(false), [](DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsCard>(sender.as<class_type>())->_OnIsClickEnabledChanged();
})
);
_contentAlignmentProperty = DependencyProperty::Register(
@ -120,14 +128,18 @@ void SettingsCard::RegisterDependencyProperties() {
L"IsActionIconVisible",
xaml_typename<bool>(),
xaml_typename<class_type>(),
PropertyMetadata(box_value(true), &SettingsCard::_OnIsActionIconVisibleChanged)
PropertyMetadata(box_value(true), [](DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsCard>(sender.as<class_type>())->_OnActionIconChanged();
})
);
_isWrapEnabledProperty = DependencyProperty::Register(
L"IsWrapEnabled",
xaml_typename<bool>(),
xaml_typename<class_type>(),
PropertyMetadata(box_value(false), &SettingsCard::_OnIsWrapEnabledChanged)
PropertyMetadata(box_value(false), [](DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsCard>(sender.as<class_type>())->_OnIsWrapEnabledChanged();
})
);
}
@ -188,30 +200,6 @@ void SettingsCard::OnPointerReleased(PointerRoutedEventArgs const& args) {
_isCursorCaptured = false;
}
void SettingsCard::_OnHeaderChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsCard>(sender.as<class_type>())->_OnHeaderChanged();
}
void SettingsCard::_OnDescriptionChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsCard>(sender.as<class_type>())->_OnDescriptionChanged();
}
void SettingsCard::_OnHeaderIconChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsCard>(sender.as<class_type>())->_OnHeaderIconChanged();
}
void SettingsCard::_OnIsClickEnabledChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsCard>(sender.as<class_type>())->_OnIsClickEnabledChanged();
}
void SettingsCard::_OnIsActionIconVisibleChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsCard>(sender.as<class_type>())->_OnActionIconChanged();
}
void SettingsCard::_OnIsWrapEnabledChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsCard>(sender.as<class_type>())->_OnIsWrapEnabledChanged();
}
static bool IsNotEmpty(IInspectable const& value) noexcept {
if (!value) {
return false;

View file

@ -63,13 +63,6 @@ private:
static DependencyProperty _isActionIconVisibleProperty;
static DependencyProperty _isWrapEnabledProperty;
static void _OnHeaderChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&);
static void _OnDescriptionChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&);
static void _OnHeaderIconChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&);
static void _OnIsClickEnabledChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&);
static void _OnIsActionIconVisibleChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&);
static void _OnIsWrapEnabledChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&);
void _OnHeaderChanged() const;
void _OnDescriptionChanged() const;
void _OnHeaderIconChanged() const;

View file

@ -90,14 +90,18 @@ void SettingsExpander::RegisterDependencyProperties() {
L"Items",
xaml_typename<IVector<IInspectable>>(),
xaml_typename<class_type>(),
PropertyMetadata(nullptr, &SettingsExpander::_OnItemsConnectedPropertyChanged)
PropertyMetadata(nullptr, [](DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsExpander>(sender.as<class_type>())->_OnItemsConnectedPropertyChanged();
})
);
_itemsSourceProperty = DependencyProperty::Register(
L"ItemsSource",
xaml_typename<IInspectable>(),
xaml_typename<class_type>(),
PropertyMetadata(nullptr, &SettingsExpander::_OnItemsConnectedPropertyChanged)
PropertyMetadata(nullptr, [](DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsExpander>(sender.as<class_type>())->_OnItemsConnectedPropertyChanged();
})
);
_itemTemplateProperty = DependencyProperty::Register(
@ -155,10 +159,6 @@ void SettingsExpander::_OnIsExpandedChanged(DependencyObject const& sender, Depe
}
}
void SettingsExpander::_OnItemsConnectedPropertyChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&) {
get_self<SettingsExpander>(sender.as<class_type>())->_OnItemsConnectedPropertyChanged();
}
void SettingsExpander::_OnItemsConnectedPropertyChanged() {
ItemsControl itemsContainer = GetTemplateChild(PART_ItemsContainer).as<ItemsControl>();
if (!itemsContainer) {

View file

@ -73,7 +73,6 @@ private:
static DependencyProperty _isWrapEnabledProperty;
static void _OnIsExpandedChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const& args);
static void _OnItemsConnectedPropertyChanged(DependencyObject const& sender, DependencyPropertyChangedEventArgs const&);
void _OnItemsConnectedPropertyChanged();

View file

@ -147,7 +147,7 @@ LRESULT CALLBACK ShortcutService::_LowLevelKeyboardProc(int nCode, WPARAM wParam
}
const DWORD code = info->vkCode;
if (code <= 0 && code >= 255) {
if (code <= 0 || code >= 255) {
that._keyboardHookShortcutActivated = false;
return CallNextHookEx(NULL, nCode, wParam, lParam);
}

View file

@ -1,4 +1,4 @@
#include "pch.h"
#include "pch.h"
#include "SimpleStackPanel.h"
#if __has_include("SimpleStackPanel.g.cpp")
#include "SimpleStackPanel.g.cpp"
@ -141,6 +141,8 @@ Size SimpleStackPanel::ArrangeOverride(Size finalSize) const {
}
switch (alignment) {
case HorizontalAlignment::Left:
break;
case HorizontalAlignment::Center:
itemRect.X = position.X + (finalSize.Width - position.X - (float)padding.Right - itemRect.Width) / 2;
break;
@ -163,6 +165,8 @@ Size SimpleStackPanel::ArrangeOverride(Size finalSize) const {
}
switch (alignment) {
case VerticalAlignment::Top:
break;
case VerticalAlignment::Center:
itemRect.Y = position.Y + (finalSize.Height - position.Y - (float)padding.Bottom - itemRect.Height) / 2;
break;

View file

@ -1,5 +1,6 @@
#include "pch.h"
#include "SmoothResizeHelper.h"
#include "Win32Helper.h"
#include <inspectable.h>
// 来自 https://github.com/ALTaleX531/TranslucentFlyouts/blob/017970cbac7b77758ab6217628912a8d551fcf7c/TFModern/DiagnosticsHandler.cpp#L71-L84
@ -17,12 +18,9 @@ namespace Magpie {
bool SmoothResizeHelper::EnableResizeSync(HWND hWnd, const winrt::Application& app) noexcept {
// UWP 使用这个未记录的接口实现平滑调整尺寸
// https://gist.github.com/apkipa/20cae438aef2a8633f99e10e0b90b11e
static auto enableResizeLayoutSynchronization = []() {
HMODULE hUser32 = GetModuleHandle(L"user32");
assert(hUser32);
using tEnableResizeLayoutSynchronization = void(WINAPI*)(HWND hwnd, BOOL enable);
return (tEnableResizeLayoutSynchronization)GetProcAddress(hUser32, MAKEINTRESOURCEA(2615));
}();
static auto enableResizeLayoutSynchronization =
Win32Helper::LoadSystemFunction<void WINAPI(HWND hwnd, BOOL enable)>(
L"user32.dll", MAKEINTRESOURCEA(2615));
// 检查是否支持 IFrameworkApplicationPrivate 接口
if (!app.try_as<IFrameworkApplicationPrivate>() || !enableResizeLayoutSynchronization) {

View file

@ -25,31 +25,50 @@ static fnAllowDarkModeForWindow AllowDarkModeForWindow = nullptr;
static fnRefreshImmersiveColorPolicyState RefreshImmersiveColorPolicyState = nullptr;
static fnFlushMenuThemes FlushMenuThemes = nullptr;
[[maybe_unused]]
static bool IsInitialized() noexcept {
return SetPreferredAppMode;
}
void ThemeHelper::Initialize() noexcept {
assert(!IsInitialized());
assert(!SetPreferredAppMode);
HMODULE hUxtheme = GetModuleHandle(L"uxtheme.dll");
assert(hUxtheme);
const HMODULE hUxtheme = GetModuleHandle(L"uxtheme.dll");
if (!hUxtheme) {
return;
}
SetPreferredAppMode = (fnSetPreferredAppMode)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135));
AllowDarkModeForWindow = (fnAllowDarkModeForWindow)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133));
RefreshImmersiveColorPolicyState = (fnRefreshImmersiveColorPolicyState)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(104));
FlushMenuThemes = (fnFlushMenuThemes)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(136));
// 先转成 void* 以避免警告
AllowDarkModeForWindow = reinterpret_cast<fnAllowDarkModeForWindow>(
reinterpret_cast<void*>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133))));
if (!AllowDarkModeForWindow) {
Logger::Get().Win32Error("获取 uxtheme.dll!AllowDarkModeForWindow 失败");
return;
}
RefreshImmersiveColorPolicyState = reinterpret_cast<fnRefreshImmersiveColorPolicyState>(
reinterpret_cast<void*>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(104))));
if (!RefreshImmersiveColorPolicyState) {
Logger::Get().Win32Error("获取 uxtheme.dll!RefreshImmersiveColorPolicyState 失败");
return;
}
FlushMenuThemes = reinterpret_cast<fnFlushMenuThemes>(
reinterpret_cast<void*>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(136))));
if (!FlushMenuThemes) {
Logger::Get().Win32Error("获取 uxtheme.dll!FlushMenuThemes 失败");
return;
}
// 最后初始化 SetPreferredAppMode
SetPreferredAppMode = reinterpret_cast<fnSetPreferredAppMode>(
reinterpret_cast<void*>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135))));
if (!SetPreferredAppMode) {
Logger::Get().Win32Error("获取 uxtheme.dll!SetPreferredAppMode 失败");
return;
}
SetPreferredAppMode(PreferredAppMode::AllowDark);
RefreshImmersiveColorPolicyState();
}
void ThemeHelper::SetWindowTheme(HWND hWnd, bool darkBorder, bool darkMenu) noexcept {
assert(IsInitialized());
SetPreferredAppMode(darkMenu ? PreferredAppMode::ForceDark : PreferredAppMode::ForceLight);
AllowDarkModeForWindow(hWnd, darkMenu);
if (SetPreferredAppMode) {
SetPreferredAppMode(darkMenu ? PreferredAppMode::ForceDark : PreferredAppMode::ForceLight);
AllowDarkModeForWindow(hWnd, darkMenu);
}
// 使标题栏适应黑暗模式
// build 18985 之前 DWMWA_USE_IMMERSIVE_DARK_MODE 的值不同
@ -63,8 +82,10 @@ void ThemeHelper::SetWindowTheme(HWND hWnd, bool darkBorder, bool darkMenu) noex
sizeof(value)
);
RefreshImmersiveColorPolicyState();
FlushMenuThemes();
if (SetPreferredAppMode) {
RefreshImmersiveColorPolicyState();
FlushMenuThemes();
}
}
}

View file

@ -60,7 +60,7 @@ void ToastService::_ToastThreadProc() noexcept {
winrt::init_apartment(winrt::apartment_type::single_threaded);
static Ignore _ = [] {
[[maybe_unused]] static Ignore _ = [] {
WNDCLASSEXW wcex{
.cbSize = sizeof(wcex),
.lpfnWndProc = _ToastWndProc,

View file

@ -129,13 +129,13 @@ static bool InstallCertificateFromPE(const wchar_t* exePath) noexcept {
blob.cbData = sizeof(friendlyName);
blob.pbData = (BYTE*)friendlyName;
if (!CertSetCertificateContextProperty(context.get(), CERT_FRIENDLY_NAME_PROP_ID, 0, &blob)) {
Logger::Get().Error("CertSetCertificateContextProperty 失败");
Logger::Get().Win32Error("CertSetCertificateContextProperty 失败");
}
}
// 安装证书
if (!CertAddCertificateContextToStore(hRootCertStore.get(), context.get(), CERT_STORE_ADD_NEWER, NULL)) {
if (GetLastError() != CRYPT_E_EXISTS) {
if (GetLastError() != (DWORD)CRYPT_E_EXISTS) {
Logger::Get().Win32Error("CertAddCertificateContextToStore 失败");
return false;
}

View file

@ -124,7 +124,7 @@ protected:
if (Win32Helper::GetOSVersion().IsWin10()) {
// 初始化双缓冲绘图
static Ignore _ = []() {
[[maybe_unused]] static Ignore _ = []() {
BufferedPaintInit();
return Ignore();
}();

View file

@ -13,5 +13,6 @@ rapidhash/1.0
MSBuildDeps
[options]
spdlog/*:header_only=True
spdlog/*:wchar_filenames=True
spdlog/*:no_exceptions=True

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.UI.Xaml" version="2.8.7" targetFramework="native" />
<package id="Microsoft.Web.WebView2" version="1.0.3296.44" targetFramework="native" />
<package id="Microsoft.Web.WebView2" version="1.0.3351.48" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.250303.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.250325.1" targetFramework="native" />
</packages>

View file

@ -1,14 +1,14 @@
//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the SmallVector class.
//
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the SmallVector class.
//
//===----------------------------------------------------------------------===//
#include "pch.h"
#include "SmallVector.h"

View file

@ -14,7 +14,7 @@ struct StrHelper {
template <typename CHAR_T>
static void Trim(std::basic_string_view<CHAR_T>& str) noexcept {
for (int i = 0; i < str.size(); ++i) {
for (size_t i = 0; i < str.size(); ++i) {
if (!isspace(str[i])) {
str.remove_prefix(i);

View file

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\Common.Pre.props" />
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{05b51bb8-08cb-4907-884f-8e2ad6bf6052}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\obj\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
<OutDir>$(SolutionDir)\bin\$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="..\Common.Pre.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared" />
@ -25,7 +25,6 @@
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<FloatingPointModel>Fast</FloatingPointModel>
<PreprocessorDefinitions>NOGDI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>

View file

@ -6,5 +6,6 @@ spdlog/1.15.3
MSBuildDeps
[options]
spdlog/*:header_only=True
spdlog/*:wchar_filenames=True
spdlog/*:no_exceptions=True

View file

@ -1,24 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\Common.Pre.props" />
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{e82b7a20-0557-4dc1-b418-87977d7450a4}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)\obj\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
<OutDir>$(SolutionDir)\bin\$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="..\Common.Pre.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="Shared" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\Common.Post.props" />
@ -26,7 +25,6 @@
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<FloatingPointModel>Fast</FloatingPointModel>
<PreprocessorDefinitions>NOGDI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>

View file

@ -6,5 +6,6 @@ spdlog/1.15.3
MSBuildDeps
[options]
spdlog/*:header_only=True
spdlog/*:wchar_filenames=True
spdlog/*:no_exceptions=True

View file

@ -5,7 +5,7 @@
<ParameterGroup>
<!-- 帮助定位 WinUI 包 -->
<WinUIWinmdPath Required="true" />
<SolutionDir Required="true" />
<ObjDir Required="true" />
<Platform Required="true" />
<WinUIDllPath Output="true" />
<WinUIPriPath Output="true" />
@ -29,7 +29,7 @@ string winuiPkgDir = WinUIWinmdPath.Substring(0, WinUIWinmdPath.Length - WinUIWi
string winuiPkgId = winuiPkgDir.Substring(winuiPkgDir.LastIndexOf('\\') + 1);
IsWinUIPrerelease = winuiPkgId.Contains("prerelease");
string intDir = $"{SolutionDir}obj\\{Platform}\\WinUI\\";
string intDir = $"{ObjDir}\\{Platform}\\WinUI\\";
// 防止多个项目并行编译导致的竞争,为了减小粒度使用 intDir 计算名字
using Mutex mutex = new(false, $"ExtractWinUIRuntime{intDir.GetHashCode()}");;
@ -203,7 +203,7 @@ File.Delete(configFileName);
<_ReferenceRelatedPaths Remove="@(_ReferenceRelatedPaths)" Condition="'%(Filename)' == 'Microsoft.UI.Xaml' And '%(Extension)' != '.winmd'" />
</ItemGroup>
<ExtractWinUIRuntime Condition="'@(_WinUIWinmdReference)' != ''" WinUIWinmdPath="@(_WinUIWinmdReference)" SolutionDir="$(SolutionDir)" Platform="$(Platform)">
<ExtractWinUIRuntime Condition="'@(_WinUIWinmdReference)' != ''" WinUIWinmdPath="@(_WinUIWinmdReference)" ObjDir="$(SolutionDir)\obj" Platform="$(Platform)">
<Output TaskParameter="WinUIDllPath" PropertyName="WinUIDllPath" />
<Output TaskParameter="WinUIPriPath" PropertyName="WinUIPriPath" />
<Output TaskParameter="IsWinUIPrerelease" PropertyName="IsWinUIPrerelease" />

View file

@ -1,30 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\Common.Pre.props" />
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{456ccae4-2c51-4cf2-8d3a-1efce8c41a2d}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)obj\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
<IntDir>$(SolutionDir)\obj\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
<OutDir>$(SolutionDir)\bin\$(Platform)\$(Configuration)\</OutDir>
<!-- 快速检查会忽略新增的 conanfile.txt不过没关系可以手动重新生成 -->
<!-- <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck> -->
</PropertyGroup>
<PropertyGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="..\Common.Pre.props" />
<PropertyGroup>
<ConfigurationType>Utility</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<ItemGroup>
<None Include="clang-cl.profile" />
<None Include="msvc.profile" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ItemGroup>
<Text Include="conanprofile.txt" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<UsingTask TaskName="FindConanFiles" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>
@ -49,7 +47,7 @@ foreach (string projectDir in Directory.GetDirectories(SrcDir)) {
string projectName = projectDir.Substring(projectDir.LastIndexOf('\\') + 1);
// 虽然会生成很多 props但既然我们只导入 conandeps.props把它作为输出就够了
string outputConandepsProps = Path.GetFullPath($"{IntDir}{projectName}\\conandeps.props");
string outputConandepsProps = Path.GetFullPath($"{IntDir}\\{projectName}\\conandeps.props");
conanFiles.Add(new TaskItem(Path.GetFullPath(conanfilePath), new Dictionary<string, string> {
{ "ProjectName", projectName },
{ "OutputConandepsProps", outputConandepsProps }
@ -62,25 +60,59 @@ ConanFile = conanFiles.ToArray();
</UsingTask>
<Target Name="BuildConanDeps" BeforeTargets="Build">
<!-- 生成的 props 文件放在 $(IntDir) 里,便于清理 -->
<FindConanFiles SrcDir="$(ProjectDir).." IntDir="$(IntDir)">
<FindConanFiles SrcDir="$(ProjectDir)\\.." IntDir="$(IntDir)">
<Output TaskParameter="ConanFile" ItemName="ConanFile" />
</FindConanFiles>
<!-- 检测每个 conanfile 是否已被更改 -->
<GetOutOfDateItems Sources="@(ConanFile)"
OutputsMetadataName="OutputConandepsProps"
TLogDirectory="$(TLogLocation)"
TLogNamePrefix="$(MSBuildProjectName)"
TrackFileAccess="$(TrackFileAccess)">
<Output TaskParameter="OutOfDateSources" ItemName="_OutOfDateConanFile"/>
<!-- 检测编译选项是否改变 -->
<PropertyGroup>
<BuildOptions Condition="$(UseClangCL)">ClangCL</BuildOptions>
<BuildOptions Condition="$(UseClangCL) And $(UseNativeMicroArch)">$(BuildOptions);UseNativeMicroArch</BuildOptions>
<BuildOptions Condition="!$(UseClangCL)">MSVC</BuildOptions>
<LastBuildOptionsFile>$(IntDir)\\last_build_options.txt</LastBuildOptionsFile>
</PropertyGroup>
<ReadLinesFromFile File="$(LastBuildOptionsFile)">
<Output TaskParameter="Lines" PropertyName="LastBuildOptions" />
</ReadLinesFromFile>
<PropertyGroup>
<BuildOptionsChanged Condition="'$(BuildOptions)' == '$(LastBuildOptions)'">false</BuildOptionsChanged>
<BuildOptionsChanged Condition="'$(BuildOptions)' != '$(LastBuildOptions)'">true</BuildOptionsChanged>
</PropertyGroup>
<WriteLinesToFile Condition="$(BuildOptionsChanged)" File="$(LastBuildOptionsFile)" Lines="$(BuildOptions)" Overwrite="true" />
<!-- 检测 profile 是否已被更改 -->
<PropertyGroup>
<ProfileName Condition="$(UseClangCL)">clang-cl.profile</ProfileName>
<ProfileName Condition="!$(UseClangCL)">msvc.profile</ProfileName>
</PropertyGroup>
<ItemGroup>
<!-- 所有 props 都视为 profile 的输出 -->
<ProfileFile Include="$(ProfileName)">
<OutputConandepsProps>@(ConanFile->'%(OutputConandepsProps)')</OutputConandepsProps>
</ProfileFile>
</ItemGroup>
<GetOutOfDateItems Sources="@(ProfileFile)" OutputsMetadataName="OutputConandepsProps" TLogDirectory="$(TLogLocation)" TLogNamePrefix="$(MSBuildProjectName)-Profile" TrackFileAccess="$(TrackFileAccess)">
<Output TaskParameter="OutOfDateSources" ItemName="OutOfDateProfile" />
</GetOutOfDateItems>
<!-- 检测每个 conanfile 是否已被更改 -->
<GetOutOfDateItems Sources="@(ConanFile)" OutputsMetadataName="OutputConandepsProps" TLogDirectory="$(TLogLocation)" TLogNamePrefix="$(MSBuildProjectName)-ConanFile" TrackFileAccess="$(TrackFileAccess)">
<Output TaskParameter="OutOfDateSources" ItemName="OutOfDateConanFile" />
</GetOutOfDateItems>
<!-- 编译选项或 profile 改变则所有 conanfile 都需要重新处理,否则只处理已更改的 conanfile -->
<ItemGroup Condition="!$(BuildOptionsChanged) And '@(OutOfDateProfile)' == ''">
<ConanFile Remove="@(ConanFile)" />
<ConanFile Include="@(OutOfDateConanFile)" />
</ItemGroup>
<PropertyGroup>
<ConanInstallArch Condition="'$(Platform)' == 'x64'">x86_64</ConanInstallArch>
<ConanInstallArch Condition="'$(Platform)' == 'ARM64'">armv8</ConanInstallArch>
<!-- 目前的依赖都不使用 RTTI -->
<AdditionalFlags>'/GR-'</AdditionalFlags>
<AdditionalFlags Condition="$(UseClangCL) And '$(Configuration)' == 'Release'">$(AdditionalFlags),'/clang:-flto'</AdditionalFlags>
<AdditionalFlags Condition="$(UseClangCL) And '$(Platform)' == 'x64'">$(AdditionalFlags),'/clang:-mcx16'</AdditionalFlags>
<AdditionalFlags Condition="$(UseClangCL) And $(UseNativeMicroArch)">$(AdditionalFlags),'/clang:-march=native'</AdditionalFlags>
<AdditionalFlags Condition="!$(UseClangCL) And '$(Configuration)' == 'Release'">$(AdditionalFlags),'/GL'</AdditionalFlags>
<FlagOptions Condition="'$(AdditionalFlags)' != ''">-c:a tools.build:cxxflags=[$(AdditionalFlags)] -c:a tools.build:cflags=[$(AdditionalFlags)]</FlagOptions>
</PropertyGroup>
<!-- 批量处理 _OutOfDateConanFile 中的元素 -->
<Exec Condition="'@(_OutOfDateConanFile)' != ''" Command="conan install &quot;%(_OutOfDateConanFile.FullPath)&quot; -pr:a=conanprofile.txt --output-folder $(IntDir)%(_OutOfDateConanFile.ProjectName) -s build_type=$(Configuration) -s arch=$(ConanInstallArch) --build=missing --no-remote --update -c tools.info.package_id:confs=['tools.build:cxxflags']" />
<!-- 批量处理 ConanFile 中的元素 -->
<Exec Condition="'@(ConanFile)' != ''" Command="conan install &quot;%(ConanFile.FullPath)&quot; -pr:a=$(ProfileName) --output-folder $(IntDir)%(ConanFile.ProjectName) -s build_type=$(Configuration) -s arch=$(ConanInstallArch) $(FlagOptions) --build=missing --update" />
</Target>
</Project>

View file

@ -0,0 +1,10 @@
[settings]
os=Windows
compiler=clang
compiler.version=19
compiler.runtime=static
compiler.cppstd=gnu17
[conf]
tools.cmake.cmaketoolchain:generator=Visual Studio 17
tools.info.package_id:confs=["tools.build:cxxflags"]

View file

@ -1,6 +1,9 @@
[settings]
os=Windows
compiler=msvc
compiler.version=194
compiler.runtime=static
compiler.cppstd=17
os=Windows
[conf]
tools.info.package_id:confs=["tools.build:cxxflags"]