三个rc文件,两个成功一个失败
- 错误代码:仅dtShare.rc加载失败
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE 4, 2 #include "res\LANDExports.rc2" // 非 Microsoft Visual C++ 编辑的资源 #include "l.CHS\afxres.rc" // 标准组件 #if !defined(_AFXDLL) #include "l.CHS\afxribbon.rc" // MFC 功能区和控制条资源 #endif #include "LAND2.rc" // share resources #include "FlowOb.rc" // share resources #include "dtShare.rc" // share resources #endif - 批量报错:
error RC2151: cannot reuse string constants, 17017(0x4279) - " error RC2151: cannot reuse string constants, 17018(0x427A) - " - 修复后写法:
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) #ifdef _WIN32 LANGUAGE 4, 2 #pragma code_page(936) #endif #include "res\LANDExports.rc2" // 非 Microsoft Visual C++ 编辑的资源 #include "l.CHS\afxres.rc" // 标准组件 #endif #include "LAND2.rc" // share resources #include "FlowOb.rc" // share resources #include "dtShare.rc" // share resources
📌 核心问题一句话总结
在
LANGUAGE条件编译块内#include一个共享资源文件(如dtShare.rc),会导致该文件中的资源 ID 与 MFC 标准资源(如afxribbon.rc)在 同一个语言上下文 下发生 ID 冲突,从而触发RC2151错误。
🔧 一、背景知识:RC 编译器如何管理资源?
Windows 资源编译器(RC)在处理 .rc 文件时,会为每个资源建立一个三元组作为唯一标识:
(资源类型, 资源ID, 语言ID)
- 只有当这三个元素完全相同时,RC 才认为是“重复定义”。
- 如果只是 ID 相同,但语言不同,RC 会认为这是两个独立的资源(例如中英文版本),这是合法的。
❌ 二、错误写法:为什么不行?
错误代码结构
// Main.rc
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#pragma code_page(936)
#include "l.CHS\afxres.rc"
#include "l.CHS\afxprint.rc"
#include "l.CHS\afxribbon.rc" // ← MFC Ribbon 资源,定义了大量 17xxx ID
#include "dtShare.rc" // ← 你的共享资源,也用了 17xxx ID(如 17123)
#endif
发生了什么?
- 所有被 include 的文件都在
LANGUAGE CHINESE上下文中被处理。 afxribbon.rc被加载 → 它内部定义了STRINGTABLE条目,例如:
→ RC 注册了一个资源:STRINGTABLE BEGIN 17123 "新建窗口" // 这是 MFC 预留的 Ribbon 字符串 END(RT_STRING, 17123, LANG_CHINESE)dtShare.rc被加载 → 它也定义了:
→ RC 尝试注册另一个资源:STRINGTABLE BEGIN IDS_EXPORT_EXCEL_PROMPT "导出数据至 Excel ..." // 假设 IDS_EXPORT_EXCEL_PROMPT = 17123 END(RT_STRING, 17123, LANG_CHINESE)- 冲突发生!
- 两个资源拥有完全相同的三元组
(RT_STRING, 17123, LANG_CHINESE)。 - RC 认为这是重复定义,抛出
RC2151: error RC2151: string constant repeats or conflicts。
- 两个资源拥有完全相同的三元组
💡 关键点
- 即使你把字符串改成空
"",只要 ID 和语言相同,就冲突。因为冲突的是“资源定义”,不是“字符串内容”。 - 只有完全删除该行,才不会注册这个 ID,从而避免冲突。
✅ 三、正确写法:为什么可以?
正确代码结构
// Main.rc
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#pragma code_page(936)
#include "l.CHS\afxres.rc"
#include "l.CHS\afxprint.rc"
#include "l.CHS\afxribbon.rc" // ← 在 CHINESE 上下文中
#endif
#include "dtShare.rc" // ← 在 #if 块 *外面*,使用默认语言上下文
发生了什么?
afxribbon.rc在LANGUAGE CHINESE块内被处理:
→ 注册资源:(RT_STRING, 17123, LANG_CHINESE)dtShare.rc在#if块之外被处理:- 此时没有显式的
LANGUAGE指令。 - RC 使用默认语言上下文:
LANG_NEUTRAL(中立语言)。
→ 注册资源:(RT_STRING, 17123, LANG_NEUTRAL)
- 此时没有显式的
- 无冲突!
- 两个资源的三元组是:
(RT_STRING, 17123, LANG_CHINESE)(RT_STRING, 17123, LANG_NEUTRAL)
- 语言ID不同 → RC 认为这是两个完全独立的资源,合法!
- 两个资源的三元组是:
🔍 四、为什么是 afxribbon.rc?其他 rc 为什么没事?
afxres.rc/afxprint.rc:它们主要占用0x7000+(28672+) 的 ID 范围。afxribbon.rc:它是 Office 风格界面引入的较新组件,专门使用17000 ~ 17999这个 ID 段。- 你的项目很可能在规划 ID 时,无意中将自定义字符串 ID(如
IDS_EXPORT_EXCEL_PROMPT)分配到了17xxx范围,恰好与afxribbon.rc重叠。
✅ 这就是为什么你确认“其他 rc 没问题”,唯独
dtShare.rc出事——因为它撞上了afxribbon.rc的专属 ID 段。
🛠 五、根本解决方案(任选其一)
| 方案 | 操作 | 优点 |
|---|---|---|
| 1. 重分配 ID | 将 dtShare.rc 中所有 ID 改为安全范围(如 1000 ~ 9999) |
一劳永逸,彻底避开 MFC 保留区 |
| 2. 保持 include 位置 | 始终将 dtShare.rc 放在 #if ... LANGUAGE ... #endif 块之外 |
无需改代码,利用语言上下文隔离 |
| 3. 显式声明中立语言 | 在 dtShare.rc 顶部加 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL |
即使被 include 到 LANGUAGE 块内,也能强制使用 NEUTRAL 上下文 |
✅ 总结对比表
| 特性 | 错误写法 | 正确写法 |
|---|---|---|
dtShare.rc 位置 |
在 #if ... LANGUAGE ... #endif 内部 |
在 #if ... LANGUAGE ... #endif 外部 |
| 语言上下文 | LANG_CHINESE |
LANG_NEUTRAL(默认) |
| 资源三元组 | (RT_STRING, 17123, CHINESE) |
(RT_STRING, 17123, NEUTRAL) |
是否与 afxribbon.rc 冲突 |
✅ 是(同语言同 ID) | ❌ 否(语言不同) |
| 编译结果 | RC2151 错误 |
成功 |
浙公网安备 33010602011771号