[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$ffaDwk9qkIJu46r7D9sYNPWpAQBJzbfNbrFmGRKLbGWM":3,"$fJU-4tot_gC5fDkujNeoE-cGsdMy5V_KcdUXLuAnTFgw":16,"$fPDIMzisck6sQX4xcQa5xSBwKopSfqwnKFypQQMoo_8k":423},{"slug":4,"title":5,"description":6,"content":7,"content_html":8,"pub_date":9,"tags":10,"draft":15},"duilib-static-build","正确编译 Duilib 静态库：避免 ATL 依赖和链接错误","详解如何用 DuiLib_Static.vcxproj 编译 Duilib 静态库，解决 VARIANT 未定义、Unicode 配置不匹配和 ATL 依赖等常见问题。","# 正确编译 Duilib 静态库：避免 ATL 依赖和链接错误\n\nDuilib 是一个流行的 Windows 界面库，被用于开发具有自定义皮肤的桌面应用（QQ、微信等早期版本均基于此类技术）。但在实际集成中，编译 Duilib 静态库时会遇到各种棘手的 ATL 依赖和链接错误。本文提供完整的解决方案。\n\n## Duilib 简介\n\nDuilib（DirectUI Library）是一个开源的 Windows DirectUI 界面库，基于 DirectX\u002FGDI+ 渲染。主要特点：\n\n- **XML 驱动布局**：界面用 XML 描述，与代码分离\n- **皮肤\u002F主题支持**：通过 XML 和图片资源实现完全自定义外观\n- **轻量**：相比 WPF\u002FQt，运行时依赖少\n- **Windows 原生**：直接调用 Win32 API，性能好\n\n## 各 Fork 对比：选哪个版本？\n\nGitHub 上有多个 Duilib 的 fork，主要分三个流派：\n\n### 1. 原版 duilib（duilib\u002Fduilib）\n\n最早的版本，由金山软件工程师 viksoe 维护。代码简洁，适合学习，但功能较少，长期未更新。\n\n```\n特点：\n- 代码量小，易于理解\n- 无 ATL 依赖（早期版本）\n- 缺少现代控件（树形控件、富文本等不完善）\n- 不支持 High-DPI\n```\n\n### 2. DuiLib_Ultimate（qdtroy\u002FDuiLib_Ultimate）\n\n在原版基础上增加了大量控件和特性，是目前维护最活跃的分支之一。\n\n```\n特点：\n- 更完整的控件集（WebBrowser 控件、Flash 控件等）\n- 支持 Alpha 混合、动画效果\n- 部分模块引入了 ATL 依赖（CString、CComPtr 等）\n- 项目配置默认使用 \u002FMD，需要修改才能静态编译\n```\n\n### 3. NIM_Duilib_Framework（netease-kit）\n\n网易云信开源的企业级版本，功能最完整但也最复杂。\n\n```\n特点：\n- 完整的 DLL 导出支持（UILIB_API 宏）\n- 支持多语言、多主题\n- 依赖较多（ATL、GDI+、D2D）\n- 有完整的示例项目\n- 使用 CMake 构建，跨 VS 版本兼容性好\n```\n\n### 选择建议\n\n| 需求 | 推荐 Fork |\n|------|----------|\n| 学习\u002F小项目 | 原版 duilib |\n| 中型项目，需要丰富控件 | DuiLib_Ultimate |\n| 企业级应用，需要完整功能 | NIM_Duilib_Framework |\n\n---\n\n## Visual Studio 2019\u002F2022 工程迁移\n\n老版本 Duilib 通常附带 VS2010\u002FVS2013 工程文件（.sln\u002F.vcxproj），在 VS2019\u002F2022 中打开时需要处理一些问题。\n\n### 步骤一：升级工程文件\n\n用 Visual Studio 打开旧版 .sln，会弹出\"项目升级向导\"。直接点\"确定\"，VS 会自动将平台工具集从 `v100`\u002F`v110` 升级到最新。\n\n如果升级后报错，手动修改 .vcxproj 文件：\n\n```xml\n\u003C!-- 找到这行 -->\n\u003CPlatformToolset>v100\u003C\u002FPlatformToolset>\n\n\u003C!-- 改成（VS2019）-->\n\u003CPlatformToolset>v142\u003C\u002FPlatformToolset>\n\n\u003C!-- 或（VS2022）-->\n\u003CPlatformToolset>v143\u003C\u002FPlatformToolset>\n```\n\n### 步骤二：处理废弃的 Windows SDK 版本\n\n老工程可能指定了 `8.1` 或 `10.0.14393.0` 等旧版 SDK。\n\n```xml\n\u003C!-- 修改为使用最新安装的 SDK -->\n\u003CWindowsTargetPlatformVersion>10.0\u003C\u002FWindowsTargetPlatformVersion>\n```\n\n在 VS2019\u002F2022 中，`10.0` 表示\"使用最新安装的 SDK 版本\"。\n\n### 步骤三：处理废弃的 API\n\nVS2019\u002F2022 对一些老式 C 函数报错（`strcpy`、`sprintf` 等）。两种处理方式：\n\n**方式 A**：添加预处理器定义（快速，不推荐生产环境）\n```\n_CRT_SECURE_NO_WARNINGS\n_CRT_NONSTDC_NO_DEPRECATE\n```\n\n**方式 B**：修改代码使用安全版本（推荐）\n```cpp\n\u002F\u002F 旧版\nstrcpy(buf, src);\n\n\u002F\u002F 新版\nstrcpy_s(buf, sizeof(buf), src);\n```\n\n### 步骤四：处理 ATL 依赖报错\n\nVS2019\u002F2022 Community Edition **默认不安装 ATL**，需要在 Visual Studio Installer 中额外勾选：\n\n```\nVisual Studio Installer\n→ 修改（你的 VS 版本）\n→ 单个组件\n→ 搜索 \"ATL\"\n→ 勾选：适用于 v142\u002Fv143 生成工具的 C++ ATL（x86 和 x64）\n→ 修改\n```\n\n---\n\n## \u002FMT vs \u002FMD 运行时库详解\n\n这是 Duilib 静态库集成中**最容易出错**的地方。\n\n### 四个选项\n\n| 选项 | 全称 | 运行时 | 适用配置 |\n|------|------|--------|----------|\n| `\u002FMT` | MultiThreaded | 静态链接 CRT | Release |\n| `\u002FMTd` | MultiThreaded Debug | 静态链接 Debug CRT | Debug |\n| `\u002FMD` | MultiThreaded DLL | 动态链接 VC 运行时 | Release |\n| `\u002FMDd` | MultiThreaded Debug DLL | 动态链接 Debug 运行时 | Debug |\n\n### 为什么混用会报错？\n\nCRT（C 运行时库）包含了 `malloc`\u002F`free`、`new`\u002F`delete`、标准容器等基础设施。当两个模块使用不同版本的 CRT 时：\n\n1. 它们各自维护独立的堆（heap）\n2. 在模块 A 中 `new` 的对象，在模块 B 中 `delete` 会崩溃\n3. 链接器检测到符号冲突时直接报错：\n\n```\nerror LNK2038: mismatch detected for 'RuntimeLibrary': \n  value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease' in duilib.lib(xxx.obj)\n```\n\n### 如何统一配置\n\n**方案一：全部使用 \u002FMT（推荐用于独立分发）**\n\n优点：可执行文件不依赖 VC 运行时，用户无需安装额外组件。\n缺点：可执行文件体积增大（通常增加 ~500KB）。\n\n**方案二：全部使用 \u002FMD（推荐用于内部工具）**\n\n优点：编译速度快，链接快，可执行文件小。\n缺点：需要用户安装对应版本的 Visual C++ Redistributable。\n\n**最重要原则：所有参与链接的 .lib 和 .obj 必须使用相同选项。**\n\n---\n\n## ATL 依赖的根因分析\n\n### ATL 是什么\n\nATL（Active Template Library）是微软提供的 C++ 模板库，主要用于 COM 编程。但 ATL 中的一些工具类（`CString`、`CRect`、`CPoint`、`CComPtr` 等）非常好用，所以很多非 COM 代码也引用了它们。\n\nDuilib 中常见的 ATL 引用：\n\n```cpp\n#include \u003Catlbase.h>   \u002F\u002F CComPtr, CComBSTR, CComVariant\n#include \u003Catlstr.h>    \u002F\u002F CString (ATL 版本)\n#include \u003Catlapp.h>    \u002F\u002F CMessageLoop, CAppModule\n#include \u003Catlwin.h>    \u002F\u002F CWindow, CWindowImpl\n#include \u003Catltypes.h>  \u002F\u002F CRect, CPoint, CSize\n```\n\n### ATL 的两种链接方式\n\n**静态 ATL**（`atls.lib`）：\n- 定义宏 `_ATL_STATIC_REGISTRY`\n- 不需要单独分发 ATL DLL\n- 但需要与 CRT 保持一致（`\u002FMT` 对应静态 ATL）\n\n**动态 ATL**（`atl.dll`）：\n- 系统自带或随 VC 运行时分发\n- 较新版本的 Windows 已内置\n\n### 去掉 ATL 依赖的方法\n\n如果你的项目不需要 COM 功能，可以用等价的 WTL 类或 STL 类替换 ATL：\n\n| ATL 类 | 替代方案 |\n|--------|---------|\n| `CString` | `std::wstring` \u002F `std::string` |\n| `CRect` | 自定义 `RECT` 包装 \u002F 直接用 `RECT` |\n| `CPoint` | `POINT` 结构体 |\n| `CSize` | `SIZE` 结构体 |\n| `CComPtr\u003CT>` | `std::shared_ptr\u003CT>` \u002F 手动 Release |\n\n在 Duilib 代码中找到所有 ATL 头文件引用，逐一替换。大多数 Duilib fork 在纯界面场景下不需要真正的 ATL COM 功能。\n\n---\n\n## 完整的 Visual Studio 项目属性配置\n\n### Duilib 静态库项目配置\n\n以下是 VS2019\u002F2022 中 Duilib.vcxproj 应有的关键配置（Release|x64 为例）：\n\n```xml\n\u003CPropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n  \u003CConfigurationType>StaticLibrary\u003C\u002FConfigurationType>\n  \u003CUseDebugLibraries>false\u003C\u002FUseDebugLibraries>\n  \u003CPlatformToolset>v143\u003C\u002FPlatformToolset>\n  \u003CWholeProgramOptimization>true\u003C\u002FWholeProgramOptimization>\n  \u003CCharacterSet>Unicode\u003C\u002FCharacterSet>\n\u003C\u002FPropertyGroup>\n\n\u003CItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n  \u003CClCompile>\n    \u003C!-- 运行时库：静态多线程 -->\n    \u003CRuntimeLibrary>MultiThreaded\u003C\u002FRuntimeLibrary>\n    \u003C!-- 预处理器定义 -->\n    \u003CPreprocessorDefinitions>\n      NDEBUG;\n      _LIB;\n      UNICODE;\n      _UNICODE;\n      UILIB_STATIC;\n      WIN32_LEAN_AND_MEAN;\n      %(PreprocessorDefinitions)\n    \u003C\u002FPreprocessorDefinitions>\n    \u003C!-- 优化级别 -->\n    \u003COptimization>MaxSpeed\u003C\u002FOptimization>\n    \u003C!-- 警告级别 -->\n    \u003CWarningLevel>Level3\u003C\u002FWarningLevel>\n    \u003C!-- 安全检查（Release 下关闭加快速度）-->\n    \u003CBasicRuntimeChecks>Default\u003C\u002FBasicRuntimeChecks>\n  \u003C\u002FClCompile>\n\u003C\u002FItemDefinitionGroup>\n```\n\n### 主项目配置\n\n```xml\n\u003CItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n  \u003CClCompile>\n    \u003CRuntimeLibrary>MultiThreaded\u003C\u002FRuntimeLibrary>\n    \u003CPreprocessorDefinitions>\n      NDEBUG;UNICODE;_UNICODE;UILIB_STATIC;%(PreprocessorDefinitions)\n    \u003C\u002FPreprocessorDefinitions>\n  \u003C\u002FClCompile>\n  \u003CLink>\n    \u003CAdditionalDependencies>\n      duilib.lib;\n      gdiplus.lib;\n      msimg32.lib;\n      imm32.lib;\n      %(AdditionalDependencies)\n    \u003C\u002FAdditionalDependencies>\n    \u003CAdditionalLibraryDirectories>\n      $(SolutionDir)lib\\$(Platform)\\$(Configuration);\n      %(AdditionalLibraryDirectories)\n    \u003C\u002FAdditionalLibraryDirectories>\n    \u003C!-- 子系统：Windows（不显示控制台窗口）-->\n    \u003CSubSystem>Windows\u003C\u002FSubSystem>\n  \u003C\u002FLink>\n\u003C\u002FItemDefinitionGroup>\n```\n\n---\n\n## 静态库 vs 动态库选择\n\n| 对比项 | 静态库（.lib） | 动态库（.dll） |\n|--------|---------------|---------------|\n| 部署 | 无需额外文件 | 需要附带 .dll |\n| 体积 | 可执行文件较大 | 多程序可共享 |\n| 版本管理 | 简单（一体化） | 可独立升级 |\n| 调试 | 方便（源码集成） | 稍复杂 |\n| ATL 冲突风险 | 较高（需统一配置） | 较低（独立命名空间） |\n\n对于单独分发的桌面应用，**静态库**通常是更好的选择：部署简单，不用担心 DLL Hell。\n\n---\n\n## ATL 依赖问题根因\n\nDuilib 的某些模块使用了 ATL 类（如 `CString`、`CRect`、ATL 智能指针等）。ATL 有两个版本：\n\n1. **ATL 动态链接版**：需要 `atl\u003CN>.dll`（随 Visual C++ 运行时分发）\n2. **ATL 静态链接版**：通过预处理器宏 `_ATL_STATIC_REGISTRY`\u002F`_ATL_DLL` 控制\n\n当你编译 Duilib 静态库并链接到你的项目时，如果运行时库设置（`\u002FMD` vs `\u002FMT`）或 ATL 配置不一致，就会出现以下错误：\n\n```\nerror LNK2038: mismatch detected for 'RuntimeLibrary': \n  value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease'\n\nerror LNK2019: unresolved external symbol __imp_AtlWinModuleRegisterWndClassInfoW\n\nerror LNK2019: unresolved external symbol _AtlBaseModule\n\nfatal error LNK1120: 3 unresolved externals\n```\n\n---\n\n## 预处理器宏配置\n\n不同 Duilib fork 可能需要不同的宏。通常需要：\n\n```cpp\n\u002F\u002F 告诉 Duilib 以静态库方式编译（不导出 DLL 符号）\n#define UILIB_STATIC\n\n\u002F\u002F 如果 Duilib 有 DLL 导出宏定义（常见于 NIM Duilib）\n\u002F\u002F 在编译 .lib 时需要定义此宏来关闭 __declspec(dllexport)\n```\n\n查看 Duilib 的 `UIlib.h` 或 `StdAfx.h`，找到类似以下代码：\n\n```cpp\n#ifdef UILIB_EXPORTS\n#  define UILIB_API __declspec(dllexport)\n#elif defined(UILIB_STATIC)\n#  define UILIB_API\n#else\n#  define UILIB_API __declspec(dllimport)\n#endif\n```\n\n编译静态库时，必须定义 `UILIB_STATIC`（或类似宏），否则所有接口都会是 `__declspec(dllimport)`，链接时会出错。\n\n---\n\n## 常见链接错误及解决\n\n### 错误 1：RuntimeLibrary mismatch\n\n```\nerror LNK2038: mismatch detected for 'RuntimeLibrary': \n  value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease' in main.obj\n```\n\n**解决**：统一所有项目（Duilib + 主项目 + 所有第三方库）的运行时库设置。\n\n### 错误 2：ATL 符号未解析\n\n```\nerror LNK2019: unresolved external symbol _AtlBaseModule\nerror LNK2019: unresolved external symbol __AtlBaseModuleClass::Init\n```\n\n**解决**：\n\n```cpp\n\u002F\u002F 在主项目的 stdafx.cpp（预编译头源文件）中添加：\n#include \u003Catlbase.h>\n#include \u003Catlapp.h>\n\n\u002F\u002F 或者确保主项目链接了正确的 ATL 库\n\u002F\u002F 项目属性 → 链接器 → 输入 → 附加依赖项\n\u002F\u002F 添加：atls.lib（静态 ATL）或 atl.lib\n```\n\n### 错误 3：_ITERATOR_DEBUG_LEVEL mismatch\n\n```\nerror LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': \n  value '0' doesn't match value '2'\n```\n\n**解决**：Duilib 和主项目必须用相同的配置（都 Debug 或都 Release）编译。\n\n### 错误 4：重复定义\n\n```\nerror LNK2005: _DllMain@12 already defined in MSVCRT.lib\nerror LNK2005: __setargv already defined\n```\n\n**解决**：\n\n```\n项目属性 → 链接器 → 命令行 → 其他选项：\n添加：\u002FNODEFAULTLIB:MSVCRT\n```\n\n或者检查是否混用了 `\u002FMT` 和 `\u002FMD`。\n\n### 错误 5：GDI+ 未链接\n\n```\nerror LNK2019: unresolved external symbol __imp__GdiplusStartup@12\n```\n\n**解决**：主项目添加依赖项 `gdiplus.lib`：\n```\n项目属性 → 链接器 → 输入 → 附加依赖项：\ngdiplus.lib\n```\n\n### 错误 6：找不到 atlbase.h\n\n```\nfatal error C1083: Cannot open include file: 'atlbase.h': No such file or directory\n```\n\n**解决**：在 Visual Studio Installer 中安装 ATL 组件：\n\n```\nVS Installer → 修改 → 单个组件\n→ 搜索 \"ATL\"\n→ 勾选 C++ ATL for latest v14x build tools (x86 & x64)\n```\n\n### 错误 7：x86\u002Fx64 架构不匹配\n\n```\nerror LNK2019: unresolved external symbol xxx referenced in function yyy\nfatal error LNK1120: N unresolved externals\n```\n\n当 Duilib.lib 编译为 x86 但主项目是 x64 时发生（或反之）。\n\n**解决**：确保 Duilib 和主项目使用相同的目标平台，分别编译 x86 和 x64 版本的 Duilib.lib。\n\n---\n\n## 最终配置清单\n\n使用以下清单逐项检查：\n\n**Duilib 项目配置**：\n- [ ] 配置类型：静态库（.lib）\n- [ ] 运行时库：`\u002FMT`（Release）或 `\u002FMTd`（Debug）\n- [ ] 预处理器：`UILIB_STATIC`、`_LIB`、`UNICODE`、`_UNICODE`\n- [ ] 字符集：Unicode\n- [ ] ATL 组件已在 VS Installer 中安装\n\n**主项目配置**：\n- [ ] 运行时库与 Duilib 一致（`\u002FMT` 或 `\u002FMD`）\n- [ ] 附加依赖项：`duilib.lib`、`gdiplus.lib`、`msimg32.lib`\n- [ ] 附加库目录：Duilib.lib 所在路径\n- [ ] 预处理器：`UILIB_STATIC`、`UNICODE`\n- [ ] 目标平台（x86\u002Fx64）与 Duilib 一致\n\n**编译顺序**：\n1. 先编译 Duilib 静态库\n2. 再编译主项目\n\n**验证**：\n- Debug 和 Release 都能正常编译链接\n- 运行时不崩溃、字体\u002F资源正常加载\n\n遵循这份清单，你的 Duilib 静态库集成就能顺利完成，避免绝大多数链接错误。\n","\u003Ch1>正确编译 Duilib 静态库：避免 ATL 依赖和链接错误\u003C\u002Fh1>\n\u003Cp>Duilib 是一个流行的 Windows 界面库，被用于开发具有自定义皮肤的桌面应用（QQ、微信等早期版本均基于此类技术）。但在实际集成中，编译 Duilib 静态库时会遇到各种棘手的 ATL 依赖和链接错误。本文提供完整的解决方案。\u003C\u002Fp>\n\u003Ch2 id=\"duilib-简介\">Duilib 简介\u003C\u002Fh2>\n\u003Cp>Duilib（DirectUI Library）是一个开源的 Windows DirectUI 界面库，基于 DirectX\u002FGDI+ 渲染。主要特点：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>XML 驱动布局\u003C\u002Fstrong>：界面用 XML 描述，与代码分离\u003C\u002Fli>\n\u003Cli>\u003Cstrong>皮肤\u002F主题支持\u003C\u002Fstrong>：通过 XML 和图片资源实现完全自定义外观\u003C\u002Fli>\n\u003Cli>\u003Cstrong>轻量\u003C\u002Fstrong>：相比 WPF\u002FQt，运行时依赖少\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Windows 原生\u003C\u002Fstrong>：直接调用 Win32 API，性能好\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"各-fork-对比-选哪个版本\">各 Fork 对比：选哪个版本？\u003C\u002Fh2>\n\u003Cp>GitHub 上有多个 Duilib 的 fork，主要分三个流派：\u003C\u002Fp>\n\u003Ch3 id=\"1-原版-duilib-duilib-duilib\">1. 原版 duilib（duilib\u002Fduilib）\u003C\u002Fh3>\n\u003Cp>最早的版本，由金山软件工程师 viksoe 维护。代码简洁，适合学习，但功能较少，长期未更新。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>特点：\n- 代码量小，易于理解\n- 无 ATL 依赖（早期版本）\n- 缺少现代控件（树形控件、富文本等不完善）\n- 不支持 High-DPI\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"2-duilib_ultimate-qdtroy-duilib_ultimate\">2. DuiLib_Ultimate（qdtroy\u002FDuiLib_Ultimate）\u003C\u002Fh3>\n\u003Cp>在原版基础上增加了大量控件和特性，是目前维护最活跃的分支之一。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>特点：\n- 更完整的控件集（WebBrowser 控件、Flash 控件等）\n- 支持 Alpha 混合、动画效果\n- 部分模块引入了 ATL 依赖（CString、CComPtr 等）\n- 项目配置默认使用 \u002FMD，需要修改才能静态编译\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"3-nim_duilib_framework-netease-kit\">3. NIM_Duilib_Framework（netease-kit）\u003C\u002Fh3>\n\u003Cp>网易云信开源的企业级版本，功能最完整但也最复杂。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>特点：\n- 完整的 DLL 导出支持（UILIB_API 宏）\n- 支持多语言、多主题\n- 依赖较多（ATL、GDI+、D2D）\n- 有完整的示例项目\n- 使用 CMake 构建，跨 VS 版本兼容性好\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"选择建议\">选择建议\u003C\u002Fh3>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>需求\u003C\u002Fth>\n\u003Cth>推荐 Fork\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>学习\u002F小项目\u003C\u002Ftd>\n\u003Ctd>原版 duilib\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>中型项目，需要丰富控件\u003C\u002Ftd>\n\u003Ctd>DuiLib_Ultimate\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>企业级应用，需要完整功能\u003C\u002Ftd>\n\u003Ctd>NIM_Duilib_Framework\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Chr>\n\u003Ch2 id=\"visual-studio-2019-2022-工程迁移\">Visual Studio 2019\u002F2022 工程迁移\u003C\u002Fh2>\n\u003Cp>老版本 Duilib 通常附带 VS2010\u002FVS2013 工程文件（.sln\u002F.vcxproj），在 VS2019\u002F2022 中打开时需要处理一些问题。\u003C\u002Fp>\n\u003Ch3 id=\"步骤一-升级工程文件\">步骤一：升级工程文件\u003C\u002Fh3>\n\u003Cp>用 Visual Studio 打开旧版 .sln，会弹出&quot;项目升级向导&quot;。直接点&quot;确定&quot;，VS 会自动将平台工具集从 \u003Ccode>v100\u003C\u002Fcode>\u002F\u003Ccode>v110\u003C\u002Fcode> 升级到最新。\u003C\u002Fp>\n\u003Cp>如果升级后报错，手动修改 .vcxproj 文件：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-xml\">&lt;!-- 找到这行 --&gt;\n&lt;PlatformToolset&gt;v100&lt;\u002FPlatformToolset&gt;\n\n&lt;!-- 改成（VS2019）--&gt;\n&lt;PlatformToolset&gt;v142&lt;\u002FPlatformToolset&gt;\n\n&lt;!-- 或（VS2022）--&gt;\n&lt;PlatformToolset&gt;v143&lt;\u002FPlatformToolset&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"步骤二-处理废弃的-windows-sdk-版本\">步骤二：处理废弃的 Windows SDK 版本\u003C\u002Fh3>\n\u003Cp>老工程可能指定了 \u003Ccode>8.1\u003C\u002Fcode> 或 \u003Ccode>10.0.14393.0\u003C\u002Fcode> 等旧版 SDK。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-xml\">&lt;!-- 修改为使用最新安装的 SDK --&gt;\n&lt;WindowsTargetPlatformVersion&gt;10.0&lt;\u002FWindowsTargetPlatformVersion&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>在 VS2019\u002F2022 中，\u003Ccode>10.0\u003C\u002Fcode> 表示&quot;使用最新安装的 SDK 版本&quot;。\u003C\u002Fp>\n\u003Ch3 id=\"步骤三-处理废弃的-api\">步骤三：处理废弃的 API\u003C\u002Fh3>\n\u003Cp>VS2019\u002F2022 对一些老式 C 函数报错（\u003Ccode>strcpy\u003C\u002Fcode>、\u003Ccode>sprintf\u003C\u002Fcode> 等）。两种处理方式：\u003C\u002Fp>\n\u003Cp>\u003Cstrong>方式 A\u003C\u002Fstrong>：添加预处理器定义（快速，不推荐生产环境）\u003C\u002Fp>\n\u003Cpre>\u003Ccode>_CRT_SECURE_NO_WARNINGS\n_CRT_NONSTDC_NO_DEPRECATE\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>方式 B\u003C\u002Fstrong>：修改代码使用安全版本（推荐）\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">\u002F\u002F 旧版\nstrcpy(buf, src);\n\n\u002F\u002F 新版\nstrcpy_s(buf, sizeof(buf), src);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"步骤四-处理-atl-依赖报错\">步骤四：处理 ATL 依赖报错\u003C\u002Fh3>\n\u003Cp>VS2019\u002F2022 Community Edition \u003Cstrong>默认不安装 ATL\u003C\u002Fstrong>，需要在 Visual Studio Installer 中额外勾选：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Visual Studio Installer\n→ 修改（你的 VS 版本）\n→ 单个组件\n→ 搜索 &quot;ATL&quot;\n→ 勾选：适用于 v142\u002Fv143 生成工具的 C++ ATL（x86 和 x64）\n→ 修改\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Chr>\n\u003Ch2 id=\"mt-vs-md-运行时库详解\">\u002FMT vs \u002FMD 运行时库详解\u003C\u002Fh2>\n\u003Cp>这是 Duilib 静态库集成中\u003Cstrong>最容易出错\u003C\u002Fstrong>的地方。\u003C\u002Fp>\n\u003Ch3 id=\"四个选项\">四个选项\u003C\u002Fh3>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>选项\u003C\u002Fth>\n\u003Cth>全称\u003C\u002Fth>\n\u003Cth>运行时\u003C\u002Fth>\n\u003Cth>适用配置\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002FMT\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>MultiThreaded\u003C\u002Ftd>\n\u003Ctd>静态链接 CRT\u003C\u002Ftd>\n\u003Ctd>Release\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002FMTd\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>MultiThreaded Debug\u003C\u002Ftd>\n\u003Ctd>静态链接 Debug CRT\u003C\u002Ftd>\n\u003Ctd>Debug\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002FMD\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>MultiThreaded DLL\u003C\u002Ftd>\n\u003Ctd>动态链接 VC 运行时\u003C\u002Ftd>\n\u003Ctd>Release\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002FMDd\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>MultiThreaded Debug DLL\u003C\u002Ftd>\n\u003Ctd>动态链接 Debug 运行时\u003C\u002Ftd>\n\u003Ctd>Debug\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Ch3 id=\"为什么混用会报错\">为什么混用会报错？\u003C\u002Fh3>\n\u003Cp>CRT（C 运行时库）包含了 \u003Ccode>malloc\u003C\u002Fcode>\u002F\u003Ccode>free\u003C\u002Fcode>、\u003Ccode>new\u003C\u002Fcode>\u002F\u003Ccode>delete\u003C\u002Fcode>、标准容器等基础设施。当两个模块使用不同版本的 CRT 时：\u003C\u002Fp>\n\u003Col>\n\u003Cli>它们各自维护独立的堆（heap）\u003C\u002Fli>\n\u003Cli>在模块 A 中 \u003Ccode>new\u003C\u002Fcode> 的对象，在模块 B 中 \u003Ccode>delete\u003C\u002Fcode> 会崩溃\u003C\u002Fli>\n\u003Cli>链接器检测到符号冲突时直接报错：\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cpre>\u003Ccode>error LNK2038: mismatch detected for 'RuntimeLibrary': \n  value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease' in duilib.lib(xxx.obj)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"如何统一配置\">如何统一配置\u003C\u002Fh3>\n\u003Cp>\u003Cstrong>方案一：全部使用 \u002FMT（推荐用于独立分发）\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>优点：可执行文件不依赖 VC 运行时，用户无需安装额外组件。\n缺点：可执行文件体积增大（通常增加 ~500KB）。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>方案二：全部使用 \u002FMD（推荐用于内部工具）\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>优点：编译速度快，链接快，可执行文件小。\n缺点：需要用户安装对应版本的 Visual C++ Redistributable。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>最重要原则：所有参与链接的 .lib 和 .obj 必须使用相同选项。\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Chr>\n\u003Ch2 id=\"atl-依赖的根因分析\">ATL 依赖的根因分析\u003C\u002Fh2>\n\u003Ch3 id=\"atl-是什么\">ATL 是什么\u003C\u002Fh3>\n\u003Cp>ATL（Active Template Library）是微软提供的 C++ 模板库，主要用于 COM 编程。但 ATL 中的一些工具类（\u003Ccode>CString\u003C\u002Fcode>、\u003Ccode>CRect\u003C\u002Fcode>、\u003Ccode>CPoint\u003C\u002Fcode>、\u003Ccode>CComPtr\u003C\u002Fcode> 等）非常好用，所以很多非 COM 代码也引用了它们。\u003C\u002Fp>\n\u003Cp>Duilib 中常见的 ATL 引用：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">#include &lt;atlbase.h&gt;   \u002F\u002F CComPtr, CComBSTR, CComVariant\n#include &lt;atlstr.h&gt;    \u002F\u002F CString (ATL 版本)\n#include &lt;atlapp.h&gt;    \u002F\u002F CMessageLoop, CAppModule\n#include &lt;atlwin.h&gt;    \u002F\u002F CWindow, CWindowImpl\n#include &lt;atltypes.h&gt;  \u002F\u002F CRect, CPoint, CSize\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"atl-的两种链接方式\">ATL 的两种链接方式\u003C\u002Fh3>\n\u003Cp>\u003Cstrong>静态 ATL\u003C\u002Fstrong>（\u003Ccode>atls.lib\u003C\u002Fcode>）：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>定义宏 \u003Ccode>_ATL_STATIC_REGISTRY\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>不需要单独分发 ATL DLL\u003C\u002Fli>\n\u003Cli>但需要与 CRT 保持一致（\u003Ccode>\u002FMT\u003C\u002Fcode> 对应静态 ATL）\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Cstrong>动态 ATL\u003C\u002Fstrong>（\u003Ccode>atl.dll\u003C\u002Fcode>）：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>系统自带或随 VC 运行时分发\u003C\u002Fli>\n\u003Cli>较新版本的 Windows 已内置\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"去掉-atl-依赖的方法\">去掉 ATL 依赖的方法\u003C\u002Fh3>\n\u003Cp>如果你的项目不需要 COM 功能，可以用等价的 WTL 类或 STL 类替换 ATL：\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>ATL 类\u003C\u002Fth>\n\u003Cth>替代方案\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>CString\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>std::wstring\u003C\u002Fcode> \u002F \u003Ccode>std::string\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>CRect\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>自定义 \u003Ccode>RECT\u003C\u002Fcode> 包装 \u002F 直接用 \u003Ccode>RECT\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>CPoint\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>POINT\u003C\u002Fcode> 结构体\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>CSize\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>SIZE\u003C\u002Fcode> 结构体\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>CComPtr&lt;T&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>std::shared_ptr&lt;T&gt;\u003C\u002Fcode> \u002F 手动 Release\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>在 Duilib 代码中找到所有 ATL 头文件引用，逐一替换。大多数 Duilib fork 在纯界面场景下不需要真正的 ATL COM 功能。\u003C\u002Fp>\n\u003Chr>\n\u003Ch2 id=\"完整的-visual-studio-项目属性配置\">完整的 Visual Studio 项目属性配置\u003C\u002Fh2>\n\u003Ch3 id=\"duilib-静态库项目配置\">Duilib 静态库项目配置\u003C\u002Fh3>\n\u003Cp>以下是 VS2019\u002F2022 中 Duilib.vcxproj 应有的关键配置（Release|x64 为例）：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-xml\">&lt;PropertyGroup Condition=&quot;'$(Configuration)|$(Platform)'=='Release|x64'&quot;&gt;\n  &lt;ConfigurationType&gt;StaticLibrary&lt;\u002FConfigurationType&gt;\n  &lt;UseDebugLibraries&gt;false&lt;\u002FUseDebugLibraries&gt;\n  &lt;PlatformToolset&gt;v143&lt;\u002FPlatformToolset&gt;\n  &lt;WholeProgramOptimization&gt;true&lt;\u002FWholeProgramOptimization&gt;\n  &lt;CharacterSet&gt;Unicode&lt;\u002FCharacterSet&gt;\n&lt;\u002FPropertyGroup&gt;\n\n&lt;ItemDefinitionGroup Condition=&quot;'$(Configuration)|$(Platform)'=='Release|x64'&quot;&gt;\n  &lt;ClCompile&gt;\n    &lt;!-- 运行时库：静态多线程 --&gt;\n    &lt;RuntimeLibrary&gt;MultiThreaded&lt;\u002FRuntimeLibrary&gt;\n    &lt;!-- 预处理器定义 --&gt;\n    &lt;PreprocessorDefinitions&gt;\n      NDEBUG;\n      _LIB;\n      UNICODE;\n      _UNICODE;\n      UILIB_STATIC;\n      WIN32_LEAN_AND_MEAN;\n      %(PreprocessorDefinitions)\n    &lt;\u002FPreprocessorDefinitions&gt;\n    &lt;!-- 优化级别 --&gt;\n    &lt;Optimization&gt;MaxSpeed&lt;\u002FOptimization&gt;\n    &lt;!-- 警告级别 --&gt;\n    &lt;WarningLevel&gt;Level3&lt;\u002FWarningLevel&gt;\n    &lt;!-- 安全检查（Release 下关闭加快速度）--&gt;\n    &lt;BasicRuntimeChecks&gt;Default&lt;\u002FBasicRuntimeChecks&gt;\n  &lt;\u002FClCompile&gt;\n&lt;\u002FItemDefinitionGroup&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"主项目配置\">主项目配置\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-xml\">&lt;ItemDefinitionGroup Condition=&quot;'$(Configuration)|$(Platform)'=='Release|x64'&quot;&gt;\n  &lt;ClCompile&gt;\n    &lt;RuntimeLibrary&gt;MultiThreaded&lt;\u002FRuntimeLibrary&gt;\n    &lt;PreprocessorDefinitions&gt;\n      NDEBUG;UNICODE;_UNICODE;UILIB_STATIC;%(PreprocessorDefinitions)\n    &lt;\u002FPreprocessorDefinitions&gt;\n  &lt;\u002FClCompile&gt;\n  &lt;Link&gt;\n    &lt;AdditionalDependencies&gt;\n      duilib.lib;\n      gdiplus.lib;\n      msimg32.lib;\n      imm32.lib;\n      %(AdditionalDependencies)\n    &lt;\u002FAdditionalDependencies&gt;\n    &lt;AdditionalLibraryDirectories&gt;\n      $(SolutionDir)lib\\$(Platform)\\$(Configuration);\n      %(AdditionalLibraryDirectories)\n    &lt;\u002FAdditionalLibraryDirectories&gt;\n    &lt;!-- 子系统：Windows（不显示控制台窗口）--&gt;\n    &lt;SubSystem&gt;Windows&lt;\u002FSubSystem&gt;\n  &lt;\u002FLink&gt;\n&lt;\u002FItemDefinitionGroup&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Chr>\n\u003Ch2 id=\"静态库-vs-动态库选择\">静态库 vs 动态库选择\u003C\u002Fh2>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>对比项\u003C\u002Fth>\n\u003Cth>静态库（.lib）\u003C\u002Fth>\n\u003Cth>动态库（.dll）\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>部署\u003C\u002Ftd>\n\u003Ctd>无需额外文件\u003C\u002Ftd>\n\u003Ctd>需要附带 .dll\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>体积\u003C\u002Ftd>\n\u003Ctd>可执行文件较大\u003C\u002Ftd>\n\u003Ctd>多程序可共享\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>版本管理\u003C\u002Ftd>\n\u003Ctd>简单（一体化）\u003C\u002Ftd>\n\u003Ctd>可独立升级\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>调试\u003C\u002Ftd>\n\u003Ctd>方便（源码集成）\u003C\u002Ftd>\n\u003Ctd>稍复杂\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>ATL 冲突风险\u003C\u002Ftd>\n\u003Ctd>较高（需统一配置）\u003C\u002Ftd>\n\u003Ctd>较低（独立命名空间）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>对于单独分发的桌面应用，\u003Cstrong>静态库\u003C\u002Fstrong>通常是更好的选择：部署简单，不用担心 DLL Hell。\u003C\u002Fp>\n\u003Chr>\n\u003Ch2 id=\"atl-依赖问题根因\">ATL 依赖问题根因\u003C\u002Fh2>\n\u003Cp>Duilib 的某些模块使用了 ATL 类（如 \u003Ccode>CString\u003C\u002Fcode>、\u003Ccode>CRect\u003C\u002Fcode>、ATL 智能指针等）。ATL 有两个版本：\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>ATL 动态链接版\u003C\u002Fstrong>：需要 \u003Ccode>atl&lt;N&gt;.dll\u003C\u002Fcode>（随 Visual C++ 运行时分发）\u003C\u002Fli>\n\u003Cli>\u003Cstrong>ATL 静态链接版\u003C\u002Fstrong>：通过预处理器宏 \u003Ccode>_ATL_STATIC_REGISTRY\u003C\u002Fcode>\u002F\u003Ccode>_ATL_DLL\u003C\u002Fcode> 控制\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>当你编译 Duilib 静态库并链接到你的项目时，如果运行时库设置（\u003Ccode>\u002FMD\u003C\u002Fcode> vs \u003Ccode>\u002FMT\u003C\u002Fcode>）或 ATL 配置不一致，就会出现以下错误：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>error LNK2038: mismatch detected for 'RuntimeLibrary': \n  value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease'\n\nerror LNK2019: unresolved external symbol __imp_AtlWinModuleRegisterWndClassInfoW\n\nerror LNK2019: unresolved external symbol _AtlBaseModule\n\nfatal error LNK1120: 3 unresolved externals\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Chr>\n\u003Ch2 id=\"预处理器宏配置\">预处理器宏配置\u003C\u002Fh2>\n\u003Cp>不同 Duilib fork 可能需要不同的宏。通常需要：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">\u002F\u002F 告诉 Duilib 以静态库方式编译（不导出 DLL 符号）\n#define UILIB_STATIC\n\n\u002F\u002F 如果 Duilib 有 DLL 导出宏定义（常见于 NIM Duilib）\n\u002F\u002F 在编译 .lib 时需要定义此宏来关闭 __declspec(dllexport)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>查看 Duilib 的 \u003Ccode>UIlib.h\u003C\u002Fcode> 或 \u003Ccode>StdAfx.h\u003C\u002Fcode>，找到类似以下代码：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">#ifdef UILIB_EXPORTS\n#  define UILIB_API __declspec(dllexport)\n#elif defined(UILIB_STATIC)\n#  define UILIB_API\n#else\n#  define UILIB_API __declspec(dllimport)\n#endif\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>编译静态库时，必须定义 \u003Ccode>UILIB_STATIC\u003C\u002Fcode>（或类似宏），否则所有接口都会是 \u003Ccode>__declspec(dllimport)\u003C\u002Fcode>，链接时会出错。\u003C\u002Fp>\n\u003Chr>\n\u003Ch2 id=\"常见链接错误及解决\">常见链接错误及解决\u003C\u002Fh2>\n\u003Ch3 id=\"错误-1-runtimelibrary-mismatch\">错误 1：RuntimeLibrary mismatch\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>error LNK2038: mismatch detected for 'RuntimeLibrary': \n  value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease' in main.obj\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>解决\u003C\u002Fstrong>：统一所有项目（Duilib + 主项目 + 所有第三方库）的运行时库设置。\u003C\u002Fp>\n\u003Ch3 id=\"错误-2-atl-符号未解析\">错误 2：ATL 符号未解析\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>error LNK2019: unresolved external symbol _AtlBaseModule\nerror LNK2019: unresolved external symbol __AtlBaseModuleClass::Init\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>解决\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-cpp\">\u002F\u002F 在主项目的 stdafx.cpp（预编译头源文件）中添加：\n#include &lt;atlbase.h&gt;\n#include &lt;atlapp.h&gt;\n\n\u002F\u002F 或者确保主项目链接了正确的 ATL 库\n\u002F\u002F 项目属性 → 链接器 → 输入 → 附加依赖项\n\u002F\u002F 添加：atls.lib（静态 ATL）或 atl.lib\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"错误-3-_iterator_debug_level-mismatch\">错误 3：_ITERATOR_DEBUG_LEVEL mismatch\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': \n  value '0' doesn't match value '2'\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>解决\u003C\u002Fstrong>：Duilib 和主项目必须用相同的配置（都 Debug 或都 Release）编译。\u003C\u002Fp>\n\u003Ch3 id=\"错误-4-重复定义\">错误 4：重复定义\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>error LNK2005: _DllMain@12 already defined in MSVCRT.lib\nerror LNK2005: __setargv already defined\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>解决\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>项目属性 → 链接器 → 命令行 → 其他选项：\n添加：\u002FNODEFAULTLIB:MSVCRT\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>或者检查是否混用了 \u003Ccode>\u002FMT\u003C\u002Fcode> 和 \u003Ccode>\u002FMD\u003C\u002Fcode>。\u003C\u002Fp>\n\u003Ch3 id=\"错误-5-gdi-未链接\">错误 5：GDI+ 未链接\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>error LNK2019: unresolved external symbol __imp__GdiplusStartup@12\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>解决\u003C\u002Fstrong>：主项目添加依赖项 \u003Ccode>gdiplus.lib\u003C\u002Fcode>：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>项目属性 → 链接器 → 输入 → 附加依赖项：\ngdiplus.lib\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"错误-6-找不到-atlbase-h\">错误 6：找不到 atlbase.h\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>fatal error C1083: Cannot open include file: 'atlbase.h': No such file or directory\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>解决\u003C\u002Fstrong>：在 Visual Studio Installer 中安装 ATL 组件：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>VS Installer → 修改 → 单个组件\n→ 搜索 &quot;ATL&quot;\n→ 勾选 C++ ATL for latest v14x build tools (x86 &amp; x64)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"错误-7-x86-x64-架构不匹配\">错误 7：x86\u002Fx64 架构不匹配\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>error LNK2019: unresolved external symbol xxx referenced in function yyy\nfatal error LNK1120: N unresolved externals\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>当 Duilib.lib 编译为 x86 但主项目是 x64 时发生（或反之）。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>解决\u003C\u002Fstrong>：确保 Duilib 和主项目使用相同的目标平台，分别编译 x86 和 x64 版本的 Duilib.lib。\u003C\u002Fp>\n\u003Chr>\n\u003Ch2 id=\"最终配置清单\">最终配置清单\u003C\u002Fh2>\n\u003Cp>使用以下清单逐项检查：\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Duilib 项目配置\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>[ ] 配置类型：静态库（.lib）\u003C\u002Fli>\n\u003Cli>[ ] 运行时库：\u003Ccode>\u002FMT\u003C\u002Fcode>（Release）或 \u003Ccode>\u002FMTd\u003C\u002Fcode>（Debug）\u003C\u002Fli>\n\u003Cli>[ ] 预处理器：\u003Ccode>UILIB_STATIC\u003C\u002Fcode>、\u003Ccode>_LIB\u003C\u002Fcode>、\u003Ccode>UNICODE\u003C\u002Fcode>、\u003Ccode>_UNICODE\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>[ ] 字符集：Unicode\u003C\u002Fli>\n\u003Cli>[ ] ATL 组件已在 VS Installer 中安装\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Cstrong>主项目配置\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>[ ] 运行时库与 Duilib 一致（\u003Ccode>\u002FMT\u003C\u002Fcode> 或 \u003Ccode>\u002FMD\u003C\u002Fcode>）\u003C\u002Fli>\n\u003Cli>[ ] 附加依赖项：\u003Ccode>duilib.lib\u003C\u002Fcode>、\u003Ccode>gdiplus.lib\u003C\u002Fcode>、\u003Ccode>msimg32.lib\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>[ ] 附加库目录：Duilib.lib 所在路径\u003C\u002Fli>\n\u003Cli>[ ] 预处理器：\u003Ccode>UILIB_STATIC\u003C\u002Fcode>、\u003Ccode>UNICODE\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>[ ] 目标平台（x86\u002Fx64）与 Duilib 一致\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Cstrong>编译顺序\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Col>\n\u003Cli>先编译 Duilib 静态库\u003C\u002Fli>\n\u003Cli>再编译主项目\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>\u003Cstrong>验证\u003C\u002Fstrong>：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Debug 和 Release 都能正常编译链接\u003C\u002Fli>\n\u003Cli>运行时不崩溃、字体\u002F资源正常加载\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>遵循这份清单，你的 Duilib 静态库集成就能顺利完成，避免绝大多数链接错误。\u003C\u002Fp>\n","2022-08-24",[11,12,13,14],"cpp","duilib","windows","mfc",false,[17,30,41,53,63,70,77,84,91,98,108,117,127,136,144,152,161,170,179,189,196,205,211,218,224,233,240,247,255,265,274,283,293,303,313,321,331,342,351,360,368,374,382,390,397,400,408,415],{"slug":18,"title":19,"description":20,"pub_date":21,"tags":22,"draft":15,"word_count":29},"ide-skills-guide","Agent Skills 完全指南：21 款第三方 Skill 深度评测与使用心得","全面评测 21 款第三方 Agent Skills，涵盖 Vue 生态、前端设计、构建工具、实用工具四大分类。从安装配置到实际使用场景，带你了解每个 Skill 的功能特点、最佳实践与使用心得。","2026-06-15",[23,24,25,26,27,28],"agent","skills","AI","效率工具","前端","Vue",4169,{"slug":31,"title":32,"description":33,"pub_date":34,"tags":35,"draft":15,"word_count":40},"linux-kernel-skeleton-struct-funcptr-container_of","Linux 内核骨架：struct、函数指针与 container_of","读懂 Linux 内核源码的三件套：巨大的 struct 组合代替继承、函数指针表实现虚派发、container_of 宏从嵌入成员找回完整对象。","2026-05-09",[36,37,38,39],"linux","kernel","C","container_of",1369,{"slug":42,"title":43,"description":44,"pub_date":45,"tags":46,"draft":15,"word_count":52},"astro-complete-guide-2025","Astro 5 深度剖析：Islands 架构原理、构建优化与 Cloudflare Workers 边缘部署","从编译器视角解析 Astro 5 的 Islands 架构实现原理，Content Layer API 的 Vite 插件机制，Server Islands 的流式渲染，以及如何在 Cloudflare Workers + D1 边缘环境下榨干性能。","2026-05-08",[47,48,49,50,51],"astro","frontend","cloudflare","performance","architecture",3663,{"slug":54,"title":55,"description":56,"pub_date":57,"tags":58,"draft":15,"word_count":62},"llm-prompt-engineering","Prompt Engineering 实战：让 LLM 真正听话的技巧","System prompt 怎么写、Few-shot 怎么设计、Chain-of-Thought 原理，以及常见失败模式和调试方法。","2026-05-03",[59,60,61],"ai","llm","工程实践",1723,{"slug":64,"title":65,"description":66,"pub_date":57,"tags":67,"draft":15,"word_count":69},"rag-system-design","RAG 系统设计：从 naive 到 production-ready","Retrieval-Augmented Generation 不只是「向量数据库 + LLM」，分块策略、召回质量、重排序、缓存才是工程核心。",[59,68,60,61],"rag",1613,{"slug":71,"title":72,"description":73,"pub_date":57,"tags":74,"draft":15,"word_count":76},"git-advanced-workflow","Git 进阶工作流：rebase、cherry-pick、bisect 的正确使用","merge 会了，但 rebase 总搞错？bisect 找 bug 提交？interactive rebase 整理历史？这篇一次说清楚。",[75,61],"git",1396,{"slug":78,"title":79,"description":80,"pub_date":57,"tags":81,"draft":15,"word_count":83},"docker-practical-guide","Docker 实战：从会用到用好","会 docker run 不够，Dockerfile 最佳实践、多阶段构建、Compose 编排、镜像瘦身才是日常真正需要的。",[82,36,61],"docker",1268,{"slug":85,"title":86,"description":87,"pub_date":57,"tags":88,"draft":15,"word_count":90},"anthropics-skills-guide","anthropics\u002Fskills：Anthropic 官方 Agent Skills 仓库解析","Anthropic 官方开源的 Agent Skills 标准仓库，127k stars，解析 SKILL.md 规范、17 个示例 skill 的设计模式，以及如何在 Claude Code \u002F Claude.ai \u002F API 中使用",[59,89,23,24],"Claude",2090,{"slug":92,"title":93,"description":94,"pub_date":57,"tags":95,"draft":15,"word_count":97},"karpathy-claude-code-guidelines","Karpathy 的 LLM 编码批评与 CLAUDE.md 最佳实践","基于 Andrej Karpathy 对 LLM 编程助手的观察，forrestchang 提炼出一个 CLAUDE.md 文件，4 条原则解决 AI 编码的典型失控问题：乱猜假设、过度设计、乱改代码、目标不清",[59,89,96,61],"Claude Code",2699,{"slug":99,"title":100,"description":101,"pub_date":57,"tags":102,"draft":15,"word_count":107},"typescript-advanced-patterns","TypeScript 高级模式：让类型系统为你工作","基础 TS 会了但类型总是 any？条件类型、映射类型、模板字面量类型、infer 关键字才是 TS 的真正威力。",[103,104,105,106],"typescript","类型系统","前端工程","高级模式",1419,{"slug":109,"title":110,"description":111,"pub_date":57,"tags":112,"draft":15,"word_count":116},"linux-performance-tuning","Linux 性能调优实战：从 top 到 perf 的完整工具链","遇到性能问题不知道从哪下手？这篇建立系统化的排查思路，从 CPU\u002F内存\u002FIO\u002F网络逐层分析。",[36,113,114,115],"性能","运维","系统编程",1524,{"slug":118,"title":119,"description":120,"pub_date":57,"tags":121,"draft":15,"word_count":126},"python-functional-programming","Python 函数式编程：map\u002Ffilter\u002Freduce 之外","Python 不是纯函数式语言，但 functools、itertools、偏函数、闭包这些工具用好了能让代码简洁一个量级。",[122,123,124,125],"python","函数式","闭包","装饰器",1867,{"slug":128,"title":129,"description":130,"pub_date":57,"tags":131,"draft":15,"word_count":135},"python-oop-guide","Python 面向对象：__init__ 之外你需要知道的","Python OOP 不只是 class + __init__，魔术方法、描述符、元类才是真正的武器。",[122,132,133,134],"OOP","面向对象","魔术方法",1792,{"slug":137,"title":138,"description":139,"pub_date":57,"tags":140,"draft":15,"word_count":143},"python-data-structures","Python 内置数据结构深度解析","list、dict、set、tuple 不只是数据容器，搞懂它们的底层实现和时间复杂度，才能写出高性能 Python。",[122,141,113,142],"数据结构","算法",1517,{"slug":145,"title":146,"description":147,"pub_date":57,"tags":148,"draft":15,"word_count":151},"python-basics-quick-start","Python 快速上手：写给有编程基础的人","已经会其他语言，想快速掌握 Python 的语法特性和思维方式，这篇是捷径。",[122,149,150],"入门","基础",1607,{"slug":153,"title":154,"description":155,"pub_date":57,"tags":156,"draft":15,"word_count":160},"python-dataclass-pydantic","Python dataclass vs Pydantic：数据类选型指南","dataclass 是标准库的轻量选择，Pydantic v2 是带验证的重武器，什么时候用哪个，这篇说清楚。",[122,157,158,159],"dataclass","pydantic","数据验证",1323,{"slug":162,"title":163,"description":164,"pub_date":57,"tags":165,"draft":15,"word_count":169},"python-asyncio-practical","Python asyncio 实战：从回调地狱到协程优雅","asyncio 是 Python 异步编程的核心，搞懂 event loop、Task、gather 这些概念才能写出真正高效的异步代码。",[122,166,167,168],"asyncio","并发","网络编程",1258,{"slug":171,"title":172,"description":173,"pub_date":57,"tags":174,"draft":15,"word_count":178},"python-type-hints-guide","Python 类型注解完全指南：从入门到实践","Python 3.5+ 引入类型注解，配合 mypy\u002Fpyright 让 Python 也能享受静态类型检查的好处。",[122,175,176,177],"typescript-style","type-hints","工具链",1102,{"slug":180,"title":181,"description":182,"pub_date":183,"tags":184,"draft":15,"word_count":188},"pwa-install-update-button","PWA 踩坑：为什么安装按钮从来不出现","从 beforeinstallprompt 到 Service Worker waiting，把 PWA 的安装与更新提示真正做对","2026-05-02",[185,186,187],"pwa","javascript","web",1683,{"slug":190,"title":191,"description":192,"pub_date":193,"tags":194,"draft":15,"word_count":195},"openclaw-vs-hermes-agent","OpenClaw vs Hermes Agent：两个本地优先 Agent 的设计差异","OpenClaw（Novita AI）和 Hermes Agent（Nous Research）都是本地运行的个人 AI Agent，但在记忆系统、技能学习、运行环境和模型生态上走了不同的路。深入对比两种架构的核心差异。","2026-05-01",[59,23,60],1679,{"slug":197,"title":198,"description":199,"pub_date":193,"tags":200,"draft":15,"word_count":204},"cpp-random-design-patterns","C++ 设计模式实战：RAII、观察者、工厂","用现代 C++（C++17\u002F20）实现三种高频设计模式：RAII 资源管理、观察者模式事件系统、工厂模式插件架构。每种模式给出问题场景、实现代码和真实工程案例。",[11,201,202,203],"设计模式","c++17","工程",2613,{"slug":206,"title":207,"description":208,"pub_date":193,"tags":209,"draft":15,"word_count":210},"data-structures-fundamentals","数据结构基础：从数组到红黑树","系统梳理常用数据结构的核心原理、时间复杂度和适用场景。数组、链表、栈、队列、哈希表、二叉树、堆、图，每种结构附实现要点和 C++ 代码片段。",[141,142,11,150],3004,{"slug":212,"title":213,"description":214,"pub_date":215,"tags":216,"draft":15,"word_count":217},"ai-agent-what-is","什么是 AI Agent？从 LLM 到自主执行","LLM 本身是无状态问答机，Agent 是什么让它’动’起来的？本文深入解析 Agent 的四个核心能力、ReAct 框架、工具调用原理，以及主流框架横向对比。","2026-04-30",[59,23,60],2116,{"slug":219,"title":220,"description":221,"pub_date":215,"tags":222,"draft":15,"word_count":223},"ai-agent-memory","AI Agent 的记忆系统：从上下文窗口到长期记忆","深入拆解 AI Agent 的四种记忆类型、上下文窗口压缩策略、RAG 向量检索原理，以及三种典型失败模式和工程选型建议。",[59,23,68],2052,{"slug":225,"title":226,"description":227,"pub_date":215,"tags":228,"draft":15,"word_count":232},"network-proxy-vpn-guide","代理与翻墙技术原理：从 HTTP 代理到现代协议","深入解析代理与 VPN 的本质区别，梳理从 SOCKS5 到 Shadowsocks、V2Ray\u002FXray、Hysteria2 的协议演进，以及机场订阅的技术本质。",[229,230,231],"网络","代理","协议",2148,{"slug":234,"title":235,"description":236,"pub_date":215,"tags":237,"draft":15,"word_count":151},"algorithm-binary-search","二分查找：永远写不对？记住这个模板","彻底搞清楚二分查找的边界问题：闭区间和左闭右开两套模板、三道经典 LeetCode 题目完整 C++ 实现，以及二分答案的进阶思路。",[142,238,239,11],"二分查找","leetcode",{"slug":241,"title":242,"description":243,"pub_date":215,"tags":244,"draft":15,"word_count":246},"algorithm-sliding-window","滑动窗口算法：从暴力到 O(n) 的思维跃迁","系统讲解滑动窗口算法的核心模板、适用题型，配合三道经典 LeetCode 题目的完整 C++ 实现，彻底理解双指针收缩思路。",[142,245,239,11],"滑动窗口",1943,{"slug":248,"title":249,"description":250,"pub_date":215,"tags":251,"draft":15,"word_count":254},"network-clash-config","Clash \u002F Mihomo 配置详解：规则、策略组与分流","深入解析 Clash\u002FMihomo 的核心配置结构，包括代理节点、策略组类型、规则优先级、DNS fake-ip 模式，以及一份实用的完整配置模板。",[229,252,230,253],"clash","配置",1292,{"slug":256,"title":257,"description":258,"pub_date":259,"tags":260,"draft":15,"word_count":264},"hid-hotplug","HID 设备热插拔检测：从 udev 到 node-hid","在 Linux 上用 node-hid + usb 库实现可靠的 USB HID 设备热插拔检测，踩坑记录","2026-04-28",[11,261,36,262,263],"hid","nodejs","electron",2039,{"slug":266,"title":267,"description":268,"pub_date":269,"tags":270,"draft":15,"word_count":273},"electron-ipc-types","Electron IPC 类型安全：从 any 到完全类型化","用 TypeScript 泛型封装 Electron IPC，彻底消灭 any，preload 契约集中管理","2026-04-25",[263,103,271,272],"ipc","vue",1446,{"slug":275,"title":276,"description":277,"pub_date":278,"tags":279,"draft":15,"word_count":282},"element-plus-popover-hide","手动关闭多个 el-popover（不用 v-model:visible）","通过 ref + Reflect.get 调用 hide() 方法手动关闭 Element Plus Popover，解释 Vue3 Proxy 导致无法直接调用实例方法的原因。","2024-10-25",[272,280,281],"element-plus","vue3",1321,{"slug":284,"title":285,"description":286,"pub_date":287,"tags":288,"draft":15,"word_count":292},"vite-vue3-ts-elementplus-pinia","用 Vite+（vp）从零搭建 Vue3 + TypeScript + Element Plus + Pinia + Vue Router","使用 Vite+ 统一工具链（vp）一条命令搭建 Vue3 全家桶，涵盖按需导入、Pinia store、路由配置，以及常见坑的解决方案。","2024-08-27",[272,289,103,280,290,291],"vite","pinia","vite-plus",1960,{"slug":294,"title":295,"description":296,"pub_date":297,"tags":298,"draft":15,"word_count":302},"cef-lnk2038-iterator-debug-level","CEF LNK2038：解决 _ITERATOR_DEBUG_LEVEL 不匹配错误","分析 CEF（Chromium Embedded Framework）集成时出现的 LNK2038 _ITERATOR_DEBUG_LEVEL 链接错误，从根本原因到解决方案的完整指南。","2024-05-07",[11,299,300,301],"CEF","Visual Studio","链接错误",1509,{"slug":304,"title":305,"description":306,"pub_date":307,"tags":308,"draft":15,"word_count":312},"npm-electron-install-fix","彻底解决 npm 安装 Electron 失败的问题","分析 npm install electron 失败的根本原因（下载二进制超时\u002F被墙），通过国内镜像（npmmirror）彻底解决，并介绍多种备选方案和常见错误排查。","2024-03-01",[263,309,310,311],"npm","前端工具链","国内镜像",1494,{"slug":314,"title":315,"description":316,"pub_date":317,"tags":318,"draft":15,"word_count":320},"git-out-of-memory","解决 git 报错：Fatal: Out of memory, malloc failed","分析 git 大仓库操作时出现 Out of memory malloc failed 的根本原因，通过调整 pack.windowMemory、http.postBuffer 和 git repack 彻底解决。","2024-01-31",[75,36,319],"工具",2244,{"slug":322,"title":323,"description":324,"pub_date":325,"tags":326,"draft":15,"word_count":330},"vmware-tools-install","在 VMware 虚拟机中安装 open-vm-tools 完整指南","详解 VMware Tools 的作用、open-vm-tools 与官方 VMware Tools 的区别，以及在 Ubuntu 虚拟机中安装并生效的完整步骤和常见问题排查。","2023-11-21",[327,36,328,329],"VMware","Ubuntu","虚拟机",2523,{"slug":332,"title":333,"description":334,"pub_date":335,"tags":336,"draft":15,"word_count":341},"load-balancing-algorithms","负载均衡算法完全指南：从轮询到一致性哈希","系统梳理静态与动态负载均衡算法，涵盖轮询、随机、权重、IP Hash、一致性 Hash、最少连接、最快响应等，并对比 Nginx、Dubbo、Spring Cloud LoadBalancer 的实现差异。","2023-11-15",[337,338,339,340],"分布式","负载均衡","Nginx","微服务",1764,{"slug":343,"title":344,"description":345,"pub_date":346,"tags":347,"draft":15,"word_count":350},"win-cw2a-ca2w","ATL 字符串转换：CW2A 与 CA2W 完全指南","详解 ATL 宏 CW2A\u002FCA2W 在 Unicode 与 ANSI 之间的字符串转换用法、头文件依赖、USES_CONVERSION 宏的作用与常见陷阱。","2023-06-09",[11,13,348,349],"ATL","字符串",1665,{"slug":352,"title":353,"description":354,"pub_date":346,"tags":355,"draft":15,"word_count":359},"csharp-sendmessage-cpp","C# 通过 SendMessage 向 C++ 窗口发送消息与字符串","使用 P\u002FInvoke 调用 user32.dll 的 SendMessage，从 C# 发送自定义 WM_USER 消息及字符串指针给 C++ 原生窗口，并在 C++ 侧正确接收和转换。",[356,11,13,357,358],"C#","互操作","PInvoke",1554,{"slug":361,"title":362,"description":363,"pub_date":364,"tags":365,"draft":15,"word_count":367},"win-postmessage-vector","Windows PostMessage 跨线程传递 std::vector 指针","通过 PostMessage 在 Windows 消息队列中传递 std::vector 指针，使用 reinterpret_cast 将指针装入 LPARAM，并在接收方正确释放内存。","2023-05-26",[11,13,366],"WinAPI",1823,{"slug":369,"title":370,"description":371,"pub_date":364,"tags":372,"draft":15,"word_count":373},"exe-dll-single-package","将 EXE 和 DLL 打包成单一可执行文件","介绍两种将 exe 和依赖 dll 打包成单文件的方案：Enigma Virtual Box 和 WinRAR 自解压，适合发布 Windows 桌面程序时简化分发流程。",[13,11,319],1619,{"slug":375,"title":376,"description":377,"pub_date":364,"tags":378,"draft":15,"word_count":381},"cpp-random-mt19937","C++ 现代随机数生成：用 mt19937 彻底告别 rand()","深入讲解为什么 rand() 不够用，以及如何用 C++11 的 \u003Crandom> 库正确生成高质量随机数，涵盖 mt19937、各种分布和线程安全。",[11,379,380],"c++11","random",1549,{"slug":383,"title":384,"description":385,"pub_date":386,"tags":387,"draft":15,"word_count":389},"win-startup-registry","C++ 实现程序开机自启动：注册表方式详解","通过操作 Windows 注册表 Run 键实现程序开机自启动，包括 HKCU 与 HKLM 区别、完整封装代码、工作目录问题和 UAC 权限处理。","2022-12-26",[13,11,388],"registry",1201,{"slug":391,"title":392,"description":393,"pub_date":394,"tags":395,"draft":15,"word_count":396},"mfc-cstring-wparam","MFC 中 CString 与 WPARAM 之间的转换","详解 MFC 消息传递中 CString 无法直接强转为 WPARAM 的原因，以及两种正确的转换方案，并介绍结构体指针传递的正确姿势。","2022-11-25",[14,11,13],1546,{"slug":4,"title":5,"description":6,"pub_date":9,"tags":398,"draft":15,"word_count":399},[11,12,13,14],2639,{"slug":401,"title":402,"description":403,"pub_date":404,"tags":405,"draft":15,"word_count":407},"mfc-dpi-adaptive","MFC 界面自适应不同分辨率","MFC 对话框程序实现控件和字体随分辨率自动缩放的完整方案，附 DPI Awareness 配置说明","2022-08-17",[14,11,13,406],"dpi",1414,{"slug":409,"title":410,"description":411,"pub_date":412,"tags":413,"draft":15,"word_count":414},"mfc-drag-window","MFC 无标题栏窗口客户区拖动：三种方法对比","MFC 对话框去掉标题栏后如何实现拖动移动窗口，三种方案完整实现与适用场景分析","2022-08-16",[14,11,13],1633,{"slug":416,"title":417,"description":418,"pub_date":419,"tags":420,"draft":15,"word_count":422},"algorithm-number-complement","整数的补数：位运算掩码解法","LeetCode 476 题，用掩码 XOR 实现整数补数，附 C++\u002FPython\u002FJava 三种实现及补数与补码的区别","2021-03-08",[142,421,239],"位运算",1374,[]]