三个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

发生了什么?

  1. 所有被 include 的文件都在 LANGUAGE CHINESE 上下文中被处理
  2. afxribbon.rc 被加载 → 它内部定义了 STRINGTABLE 条目,例如:
    STRINGTABLE
    BEGIN
        17123 "新建窗口" // 这是 MFC 预留的 Ribbon 字符串
    END
    
    → RC 注册了一个资源:(RT_STRING, 17123, LANG_CHINESE)
  3. dtShare.rc 被加载 → 它也定义了:
    STRINGTABLE
    BEGIN
        IDS_EXPORT_EXCEL_PROMPT "导出数据至 Excel ..." // 假设 IDS_EXPORT_EXCEL_PROMPT = 17123
    END
    
    → RC 尝试注册另一个资源:(RT_STRING, 17123, LANG_CHINESE)
  4. 冲突发生!
    • 两个资源拥有完全相同的三元组 (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 块 *外面*,使用默认语言上下文

发生了什么?

  1. afxribbon.rcLANGUAGE CHINESE 块内被处理:
    → 注册资源:(RT_STRING, 17123, LANG_CHINESE)
  2. dtShare.rc#if之外被处理:
    • 此时没有显式的 LANGUAGE 指令。
    • RC 使用默认语言上下文LANG_NEUTRAL(中立语言)。
      → 注册资源:(RT_STRING, 17123, LANG_NEUTRAL)
  3. 无冲突!
    • 两个资源的三元组是:
      • (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 错误 成功

posted on 2026-04-13 10:48  长风青云  阅读(46)  评论(0)    收藏  举报