关于资源加载问题,100分

lvdalin 2011-07-14 01:02:06
我在VC的资源中,加了一个标准菜单资源,ID为IDR_MAIN.类型当然就是Menu了。
当然,通过:
HMENU hMenu = LoadMenu(NULL, MAKEINTRESOURCE(IDR_MAIN));
可以得到HMENU类型的返回值。或者,通过:

CMenu menu;
menu.LoadMenu(IDR_MAIN);

也可以直接把Menu attach到CMenu中。

由于种种原因。我现在,需要通过字符串“IDR_MAIN”(注意,不是ID宏)来得到Menu,不知道是否可行?并且,在VC资源管理器中,IDR_MAIN 前后也不能加引号。

类似于下面的伪代码:

HMENU hMenu = LoadMyMenu("IDR_MAIN"); // 通过字符串来得到。
...全文
309 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
lvdalin 2011-07-18
  • 打赏
  • 举报
回复
谢谢大家回复,还有其它更好的意见吗?
psbeond 2011-07-17
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 lisunlin0 的回复:]
怎么说呢...楼主的愿望很好,可是没有办法实现.

以一个普通win32窗口程序为例,其中代码为test.cpp, 资源为test.rc, 资源头文件为resource.h, 在resource.h里面定义了资源文件的访问宏,即类似IDR_MAIN这样的宏.编译时
test.cpp + resource.h -> test.obj
test.rc + resource.h -> test.……
[/Quote]

你这么一说,看来此路不通了。

------------------------------------------------------------------------
向立天 2011-07-16
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 psbeond 的回复:]

引用 19 楼 xianglitian 的回复:
引用 18 楼 psbeond 的回复:

引用 17 楼 xianglitian 的回复:
引用 16 楼 lvdalin 的回复:

所以,现在需要的是与Stringizing operator(#)相反的功能。

没有办法
比如我是用户
我的ID_MENU可以设成2000也可以设成3000
这完全看我心情
你凭什么能……
[/Quote]
你说的我知道
不过我觉得楼主的问题本身逻辑有些乱
或许是我没有正确理解
sunlin7 2011-07-16
  • 打赏
  • 举报
回复
怎么说呢...楼主的愿望很好,可是没有办法实现.

以一个普通win32窗口程序为例,其中代码为test.cpp, 资源为test.rc, 资源头文件为resource.h, 在resource.h里面定义了资源文件的访问宏,即类似IDR_MAIN这样的宏.编译时
test.cpp + resource.h -> test.obj
test.rc + resource.h -> test.res
链接test.res+test.obj+*.obj -> test.exe
代码与资源的同步,是依靠resource.h来完成的.
其中test.res是二进制文件,用VS打开查看,可以看到,宏定义资源已经完全用实际的数字替换了(如果是字符串定义,就还会是字符串),就是说编译后的得到的res文件,已经完全无法知道当初定义资源的宏名字了.

所以IDR_MAIN这个资源宏,编译后是不可逆的,因此楼主想完全不改动客户的习惯而使用字符串来查询原始宏定义的资源是无法做到的.

楼主换一下思路,把客户定义的资源作为一个黑盒来分析,可能会有其它更巧妙的办法.
psbeond 2011-07-16
  • 打赏
  • 举报
回复
所以说,楼主的问题,还是有相当难度的,我查了查csdn,以前也有很多人问过。都有没答案。

------------------------------------------------------------------------
psbeond 2011-07-15
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 xianglitian 的回复:]
引用 16 楼 lvdalin 的回复:

所以,现在需要的是与Stringizing operator(#)相反的功能。

没有办法
比如我是用户
我的ID_MENU可以设成2000也可以设成3000
这完全看我心情
你凭什么能知道我把这个值设成了多少
单单把ID_MENU这个字符串转换成所谓的整数
你没有任何依据
[/Quote]

我认为是有可能实现的。

#define IDR_MAIN 1000
由宏的字符串"IDR_MAIN",得到宏的值IDR_MAIN或1000。目前看来,或许有点难。

但通过菜单ID字符串"IDR_MAIN",得到菜单句柄,我坚信是可以实现的,因为FindResource已经实现了。
FindResource要求传入资源的字符串,不过这个字符串包含两种情况:
1.如果在Resource.h中,包含了IDR_MAIN的宏定义,不论在VC的资源编辑器中,IDR_MAIN加不加引号,那么这个字符串只需要把IDR_MAIN宏直接强制转成字符串指针即可。
HRSRC hRsrc = FindResourceA(NULL, (LPSTR)((DWORD)((WORD)(IDR_MAIN))), RT_MENU);
同时,VC也为我们提供了MAKEINTRESOURCE宏来做这个类型转换:
HRSRC hRsrc = FindResourceA(NULL, MAKEINTRESOURCE(IDR_MAIN), RT_MENU);
这种情况,虽然看上去传的是字符串指针,但仍然使用的是宏的数值。

2.如果在Resource.h中,没有IDR_MAIN的宏定义,那么VC的资源编辑器中,会自动为IDR_MAIN加上引号的(当添加IDR_MAIN时,如果没有引号,在Resource.h中,会自动生成#define IDR_MAIN 1000这样的定义。这时,手动删除这行定义,回到VC的资源编辑器中,会发现: IDR_MAIN被自动加上了引号)。
这时,直接通过"IDR_MAIN"字符串,就可以成功加载菜单:
HRSRC hRsrc = FindResourceA(NULL, "IDR_MAIN", RT_MENU);
这种情况下,"IDR_MAIN"是以字符串形式存在的。

通过以上试验,我们可以大致猜测FindResource是如何工作的:

看一下MAKEINTRESOURCEA的定义:
#define MAKEINTRESOURCEA(i) (LPSTR)((DWORD)((WORD)(i)))
把参数i先转成了16位的WORD,意在把i的高16位置成零:
如果FindResource传进来的资源名参数的值在0-0xFFFF,就认为是传入的是ID值,否则就被认为是普通字符串。这说明:FindResource,是认可普通字符串作为参数的,内部也可以通过字符串,来找到真正的资源!
向立天 2011-07-15
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 lvdalin 的回复:]

所以,现在需要的是与Stringizing operator(#)相反的功能。
[/Quote]
没有办法
比如我是用户
我的ID_MENU可以设成2000也可以设成3000
这完全看我心情
你凭什么能知道我把这个值设成了多少
单单把ID_MENU这个字符串转换成所谓的整数
你没有任何依据
psbeond 2011-07-15
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 xianglitian 的回复:]
引用 18 楼 psbeond 的回复:

引用 17 楼 xianglitian 的回复:
引用 16 楼 lvdalin 的回复:

所以,现在需要的是与Stringizing operator(#)相反的功能。

没有办法
比如我是用户
我的ID_MENU可以设成2000也可以设成3000
这完全看我心情
你凭什么能知道我把这个值设成了多少
单单把ID_MENU这个字……
[/Quote]

向老板,当#define IDR_MAIN 1000没有定义的时候,是使用的"IDR_MAIN"字符串。而不是1000强制类型转化成的字符串。

CString strName = "IDR_MAIN";
FindResource(NULL, strName.GetBuffer(0), RT_MENU);是可以的。

所以,我的观点是,应该可以实现,但我也不知道如何实现,我查了查EnumResourceNames,对于在Resource.h中定义了数值的资源,返回"#1000"这样的名字,对于没有定义数值的资源,返回真实的资源名,像"IDR_MAIN"这样的。
信阳毛尖 2011-07-15
  • 打赏
  • 举报
回复
从头到尾看了一遍帖子,觉得学术研究的思想挺浓厚,不得不支持一下!
向立天 2011-07-15
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 psbeond 的回复:]

引用 17 楼 xianglitian 的回复:
引用 16 楼 lvdalin 的回复:

所以,现在需要的是与Stringizing operator(#)相反的功能。

没有办法
比如我是用户
我的ID_MENU可以设成2000也可以设成3000
这完全看我心情
你凭什么能知道我把这个值设成了多少
单单把ID_MENU这个字符串转换成所谓的整数
你没有任何依据

……
[/Quote]
你说的是没错
不过FindResource的字符串和你说的字符串不是一个东西
比如
#define ID_MENU 1000
FindResource是把1000变成字符串
而你想想直接用本来和字符串没什么关系的ID_MENU作为字符串
不过你说可以实现着我不反对
就是加一级映射
问题是你好像并不象这么做
而且说实话我确实不太清楚你到底想做出个什么样的东西
最后
祝你成功
lvdalin 2011-07-14
  • 打赏
  • 举报
回复
所以,现在需要的是与Stringizing operator(#)相反的功能。
lvdalin 2011-07-14
  • 打赏
  • 举报
回复
现在,可以通过IDR_MENU这样的宏,得到"IDR_MENU"这样的字符串了。原来c++语言,还提供了这种机制,真不错。
就是通过Stringizing operator(#).

#define stringer(x) #x
CString str = stringer(IDR_MAIN);
那么str的值就是"IDR_MAIN"字符串。
lvdalin 2011-07-14
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 xianglitian 的回复:]
你先看一下MAKEINTRESOURCE的定义
http://baike.baidu.com/view/2899077.htm
访问资源都是通过字符串的方式的
只不过这个字符串不是你理解的那个样子
所以你的问题就是一个映射问题
我不明白的是什么叫“希望不改变用户的习惯”
你在做IDE?
[/Quote]

对。写界面库,我希望用户在界面库里,直接把menu id的字符串写进去,我的界面库就能直接加载菜单了。我不能要求,用我界面库的人,把ID加上引号吧?
向立天 2011-07-14
  • 打赏
  • 举报
回复
你先看一下MAKEINTRESOURCE的定义
http://baike.baidu.com/view/2899077.htm
访问资源都是通过字符串的方式的
只不过这个字符串不是你理解的那个样子
所以你的问题就是一个映射问题
我不明白的是什么叫“希望不改变用户的习惯”
你在做IDE?
lvdalin 2011-07-14
  • 打赏
  • 举报
回复
研究了一下,资源加不加引号,唯一的区别就是:
加了引号,resource.h中就不生成ID宏定义,不加引号,就生成宏定义。

如果一个不加引号的ID,在resource.h中生成了宏定义后,你手动把这个宏定义删除,转到vc的资源编辑器后会发现,vc自动帮你加上了引号。

所以,像下面的代码:
HRSRC hRsrc = FindResourceA(NULL, "IDR_MAIN1", RT_MENU);
我猜想VC是先判断IDR_MAIN1这个宏有没有定义,如果没有,就去在资源中搜索"IDR_MAIN1"。
所以FindResourceA这个函数内部,是可以区别IDR_MAIN1这个宏和"IDR_MAIN1"这个字符串的。

所以我在调用FindResourceA前,只需要把IDR_MAIN1这个宏undefine掉,应该就可以了。
现在的问题就变成了:如何由"IDR_MAIN1"这个字符串,但到IDR_MAIN1这个宏?
Liekkas 2011-07-14
  • 打赏
  • 举报
回复
lvdalin 2011-07-14
  • 打赏
  • 举报
回复
想想,好像这个功能没办法实现。除非是VC提供了“宏”字符串与宏值的互转函数。VC编译项目的时候,是一定有这样的函数的,估计没有开放出来。
lvdalin 2011-07-14
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 kyotrue 的回复:]
在资源编辑器里面以字符串方式定义资源,不要用数字。带上引号就是字符串,比如"IDR_MENU1",使用的时候不包括引号,LoadMyMenu("IDR_MAIN")就行,而不用LoadMyMenu("\"IDR_MAIN\"")
[/Quote]

我在主贴中就说了,希望不改变用户的习惯,仍然定义不加引号的字符串ID,也就是,仍然定义成IDR_MAIN,而不是IDR_MAIN。
用试了FindResource,好像也不起作用。
kyotrue 2011-07-14
  • 打赏
  • 举报
回复
在资源编辑器里面以字符串方式定义资源,不要用数字。带上引号就是字符串,比如"IDR_MENU1",使用的时候不包括引号,LoadMyMenu("IDR_MAIN")就行,而不用LoadMyMenu("\"IDR_MAIN\"")
lvdalin 2011-07-14
  • 打赏
  • 举报
回复
感谢楼上几位,不过问题还是没解决,我说一下我的原始需求:
我需要动态创建界面,包含菜单栏,我把控件什么的,都保存到xml文件中,然后根据这个xml文件,来动态生成界面。因为,我的菜单是需要换肤的,所以,我需要在xml中,指定动态创建的菜单ID项,这个菜单是在VC中创建的,虽然我可以把vc生成的resource.h中菜单栏的ID整数值写到xml中,但这样不直观,也不方便阅读,另外,如果菜单栏的ID值变了的话,我xml中的数值还需要改变。所以,我希望在xml中,保存成菜单ID的字符串,类似于:
<Menubar ID="IDR_MENU" Color="#00FF00FF">

这比
<Menubar ID="131" Color="#00FF00FF">
我觉得更好一些。

这样问题就来了: 如何通过IDR_MENU这个字符串,来加载Menu?
加载更多回复(5)

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧