www.Walzer.cn - 原创技术博客

专注于智能手机上的APP和BSP开发。
所谓高手,也就是熟悉别人制定的游戏规则、并且能在规则内跳舞的人。
posts - 59, comments - 419, trackbacks - 1, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

对WINCE中各种音量设置一点见解

Posted on 2008-02-20 09:41 Walzer 阅读(855) 评论(22)  编辑 收藏

作者: liswei

Walzer声明:此文为我同事所写, 文中参考引用了norains的<WinCE系统音量的设置>一文, 文中的CReg.h则出自微软WINCE500\PUBLIC下的公开代码. 网友若对文中一些技术细节有疑问, 可以移步到norains博客(http://blog.csdn.net/norains/)的相关文章下向norains请教

 

-----------------
最近一段时间在修改音量需求变化的时候,让我对在WINCE下对各种音量的设置有了一定的理解,现在将我的理解写到blog上,让各位指教。

首先我们来看下,这些声音设置都在注册表:HKEY_CURRENT_USER\ControlPanel\Volume下,里面的几个键值都是控制声音的。先解释如下:

Volume: 系统的主音量,范围是0x0 ~ 0xFFFFFFFF.
       
Screen: 屏幕敲击声. 当数值为0(或65536)无声,1为柔和,65538为洪亮

Key: 键盘敲击声,数值的意义和Screen相同.
       
Mute: 控制其它静音的选项. 置0x04位为1时允许事件声音,0x02允许应用程序声音,0x01允许警告声.需要注意的是,如果不允许应用程序声音,则警告声位也将被忽略.

知道各个键值的意义后,我从最主要的系统的主音量Volume说起。

一、对系统主音量Volume的操作

首先我们来看一段最简单的改变音量的代码:          

DWORD dwVolume = 0xAAAAAAAA;
waveOutSetVolume(
0,dwVolume);    

    
waveOutSetVolume()的第一个参数是设备ID,因为需要更改的是整个系统音量,所以在这里直接取0值即可;第二个参数是需要设置的音量数值,范围是从 0x0 ~ 0xFFFFFFFF。

通过waveOutSetVolume()这个API,我们可以很容易的更改系统设备的音量,但这个时候,如果你去查看注册表的Volume的键值是没有变化的,因为它只修改了设备的音量,变化还没有这么快到达注册表。但你可以到“控制面板”中的“音量与声音”打开一下,注册表的值也随之改变。(反之,通过对注册表的单独操作对具体音量是起不到作用的)

所以,我对音量的操作,首先对注册表中的Volume进行操作,在用waveOutSetVolume()这个API具体改变音量,这样可以达到一致。具体操作代码如下:

DWORD dwVolume = 0;
CReg* pVolumeReg = NULL;

 pVolumeReg = new CReg( HKEY_CURRENT_USER, TEXT("ControlPanel\\Volume") );

 dwVolume = pVolumeReg->ValueDW(TEXT("Volume"));
。。。。。。。。。。。。。。对音量的具体设置

if( waveOutSetVolume(NULL, dwVolume) != MMSYSERR_NOERROR )           音量设置是否成功
 {
  DBGMSG(ZONE_1, (TEXT("waveOutSetVolume failed, [MainLayere.cpp, SetVolume]")));
 }
 
 pVolumeReg->SetDW(TEXT("Volume"),dwVolume); 设置注册表
 delete pVolumeReg;
 pVolumeReg = NULL;   

 上面用到的CReg是一个对注册表操作的类,是我们小组用的一个基类(Walzer注:在WINCE500目录下搜索CReg可以找到, 其实微软的人也很懒)。这样我们对主音量设置就很完善了。

二、对硬件按键声音(KEY键值)的设置

       尽管waveOutSetVolume()这个API对主音量设置很好用,但这个函数的功能却也是非常有限的,也就是说,它只能更改系统的主音量;如果想修改硬件按键声音或屏幕敲击声,则就无能为力.
        
        有些比较细心的朋友可能会从"控制面板"的"声音"入手,发现每次在控制面板调节声音,相应的"ControlPanel\Volume"下的键值数值都会变更.但如果是直接修其下的改注册表,却是无论如何都达不到相应的功能的----因为没有通知系统,注册表已经被修改.
       
        如果需要告知系统,注册表已经修改,并请系统依照修改的数值来更改音量,则需要调用微软一个未公开的API:AudioUpdateFromRegistry().
       
        这个API在文档中是无法搜索到,如果需要调用这个函数,可以有两种方法.
       
        一是直接包含"pwinuser.h"文件,然后直接调用.
       
        二是调用coredll.dll库,引出该函数并使用.
        
       第一种方法比较不稳定,因为有一些人的sdk中没有这个pwinuser.h文件,所以程序找不到。我还是推荐用第二种方法,直接调用该API(就象我们组长说的暴力调用API,这个方法真的还是不错的。)

    其具体代码如下: 

 

 1typedef void (WINAPI *DLL_AUDIOUPDATEFROMREGISTRY)();定义一个新类型指针,指向WINAPI
 2
 3    DLL_AUDIOUPDATEFROMREGISTRY Dll_AudioUpdateFromRegistry = NULL; 
 4    HINSTANCE hCoreDll = LoadLibrary(TEXT("coredll.dll")); 
 5    if (hCoreDll) 
 6    
 7        Dll_AudioUpdateFromRegistry = (DLL_AUDIOUPDATEFROMREGISTRY)GetProcAddress(hCoreDll, _T("AudioUpdateFromRegistry"));   调用该API
 8        if (Dll_AudioUpdateFromRegistry) 
 9        
10            (Dll_AudioUpdateFromRegistry)(); 
11        }
 
12        else
13        {
14            return FALSE;
15        }

16        FreeLibrary(hCoreDll); 
17    }
 
18    else
19    {
20        return FALSE;
21    }

22    return TRUE;
23

这样通过修改注册表Key键值,然后通过调用该方法就能实现对按键声音的设置。

对Screen和Mute的设置也可以用该方法,至此,对WINCE各种音量的设置就基本掌握了。希望能给大家点帮助。


Walzer评点:
这篇文章不仅写的是WaveOutSetVolume这个API的使用, 还包括了系统注册表里对应于控制面板音量调节的修改. 并且提到了我们惯用的“暴力调用API”方法。

Feedback

#1楼    回复  引用    

2008-03-05 12:49 by wangyefox [未注册用户]
不知道怎么样才能调用函数:WaveOutSetVolume,
我按网上的介绍是使用winmm.dll,但是在我手机的wm6.0操作系统上,并不存在winmm.dll文件,函数调用失败,请问,这怎么解决呢?

#2楼 [楼主]   回复  引用  查看    

2008-03-06 09:35 by Walzer      
@wangyefox
MSDN上关于WaveOutSetVolume的说明是,属于Coredll.lib里面,也就是说它属于Coredll.dll提供的函数, 而不是winmm.dll.

要看你所谓的"调用不到"是COMPILE错误,还是LINK错误了.
如果是COMPILE错误的话,那么你没有INCLUDE Mmsystem.h这个头文件
如果是LINK错误的话, 你可以在我BLOG里搜索"暴力调用API"关键字,使用暴力调用的方法来解决.

#3楼    回复  引用    

2008-03-10 16:36 by wangye [未注册用户]
改为:Coredll.dll,立即成功了!

非常感谢!!!

我在网上查的很多例子,都是说调用winmm.dll,实在是极大的错误啊。

#4楼 [楼主]   回复  引用  查看    

2008-03-11 08:57 by Walzer      
@wangye
恭喜恭喜. 我刚才很好奇查了一下, 结果winmm是用在Windows NT/2000/XP/95/98/Me上面的. 你所搜到的,多数是在谈论PC上编程的啦

#5楼    回复  引用    

2008-04-10 17:45 by Kroc [未注册用户]
看过,但是我还是遇到了问题啊~~~
调用waveOutSetVolume()之后,修改一下系统铃音(听筒的,就是右边的那个),然后注册表中的Volume会变成一个不常规的值~~~往往很小~~~
不知楼主知道为何不?如何能解决?

#6楼    回复  引用    

2008-04-11 14:45 by Kroc [未注册用户]
问题已解决~~
嘿嘿~~

#7楼    回复  引用    

2008-07-18 16:43 by 李常青 [未注册用户]
你好,1,请问为什么我在我的注册表里找不到HKEY_CURRENT_USER\ControlPanel\Volume
2,用waveOutSetVolume()这个API具体改变音量那段代码上在哪儿改啊?
应该不是在PB的注册表里吧?请问具体在哪儿改?

#8楼 [楼主]   回复  引用  查看    

2008-07-18 17:48 by Walzer      
@李常青
1. 那个注册表键值是有的. 文章是写WINCE5里面的,我拿自己现在WM6.1的手机上也有. 你细心点, HKEY_CURRENT_USER下面有个是Control Panel带空格的,有个是ControlPanel不带空格的. 不带空格下面的这个才有Volume

2. waveOutSetVolume函数放在应用层调用比较好

#9楼    回复  引用    

2008-07-25 12:32 by qiuqiu_emb [未注册用户]
那几个RETURN 干什么?

#10楼    回复  引用    

2008-07-25 15:34 by qiuqiu_emb [未注册用户]
Creg这个类呢?能否共享?

#11楼    回复  引用    

2008-07-25 15:47 by qiuqiu_emb [未注册用户]
  试了下,奇怪,暴力调用AudioUpdateFromRegistry后,就点击屏幕一直没声音了,怎么也切不回有声音!不管是设1柔和还是65538洪亮!
  WHY????
  是否还有参数设定??

#12楼 [楼主]   回复  引用  查看    

2008-07-25 17:16 by Walzer      
@qiuqiu_emb

1. return干什么:出错处理啊,你不能指望API就能一定处理正确返回正确结果. 那段代码是从一个函数里截出来的.

2. CReg.h在MOBILE还是WINCE的微软提供开放部分代码里有, 你可以搜一下, 直接拿来用

3. 这文章是我同事写的,你调用那API后为什么没有声音,这个我也不太清楚WHY了. 但那个API是没有不带参数的这个可以确认. 可能是你在注册表里改错键值了吧. 你先看一下如果在控制面板里调整的话,究竟会影响哪个键值.

#13楼    回复  引用    

2008-07-28 11:17 by qiuqiu_emb [未注册用户]
谢谢BY WALZER 的回复.
我的每次改动注册表都是成功的.
我现在呢,遇到的难题是,改动音量是可以成功的,就是改动屏幕敲击声无效(虽然注册表的改动是成功的,SCREEN键).这和我改动USB的工作模式是一样的问题。
能否给个可用例子(EVC工程),我们用的是基于ARM9的WINCE平台,我EMAIL:pqw_pengqiuwen@sina.com

#14楼    回复  引用    

2008-07-28 11:21 by qiuqiu_emb [未注册用户]
这里我给个我的调用方法:希望给为提提意见!
void CSoundDlg::OnSoft()
{
// TODO: Add your control notification handler code here
//点击屏幕声 Screen 0:无声 1:柔和 65538:洪亮
LPCTSTR Screen=_T("Screen");
WCHAR ScreenNumber[30] = _T("1");
LPCTSTR son_Key=_T("ControlPanel\\Volume\\");
DWORD ReturnValue=RegOpenKeyEx(HKEY_CURRENT_USER,son_Key,0,0,&m_hKey);
if(ReturnValue==ERROR_SUCCESS)
{
DWORD SetValue=RegSetValueEx(m_hKey,Screen,0,REG_SZ,(const unsigned char*)ScreenNumber,wcslen(ScreenNumber)*2+1);
}
RegCloseKey(m_hKey);


//调用API函数AudioUpdateFromRegistry,通知系统已对注册表做修改。
DLL_AUDIOUPDATEFROMREGISTRY Dll_AudioUpdateFromRegistry = NULL;
HINSTANCE hCoreDll = LoadLibrary(TEXT("coredll.dll"));
if (hCoreDll)
{
Dll_AudioUpdateFromRegistry = (DLL_AUDIOUPDATEFROMREGISTRY)GetProcAddress(hCoreDll, _T("AudioUpdateFromRegistry"));
if (Dll_AudioUpdateFromRegistry)
{
(Dll_AudioUpdateFromRegistry)();
//AudioUpdateFromRegistry();
}
printf("screen soft!\n");

FreeLibrary(hCoreDll);
}

//CSysVolume sysVol;
//sysVol.EnableSoundEvent(TRUE);
//sysVol.SetVolumeScreenTap(VOL_SOFT);
}

#15楼    回复  引用    

2008-07-28 21:16 by norains [未注册用户]
转载文章我不反对,只要能保持原作者的信息;但像博主这种将别人的文章,随意变更次序,然后再改一些语句,就作为自己的成果发表,我不知道应该是否表示敬意?
不妨和这篇文章比较一下,看看有多少文字雷同?
http://blog.csdn.net/norains/archive/2007/04/08/1556912.aspx#860536

"上面用到的CReg是一个对注册表操作的类,是我们小组用的一个基类(Walzer注:在WINCE500目录下搜索CReg可以找到, 其实微软的人也很懒)。"
搞得这么神秘,想请问一下:CReg是你们小组自己写的,还是拿直接拿微软的?或是直接从这篇文章中弄过来的?http://blog.csdn.net/norains/archive/2007/06/20/1659925.aspx
当然,我觉得自己应该相信是你们小组写的。

#16楼    回复  引用    

2008-07-29 09:32 by qiuqiu_emb [未注册用户]
  norains和liswei的文章我都看过,也不清楚最原始作者谁,但我想对大家有帮助的东西我们都是欢迎的.但我还是讲一点事实,文章的发表时间为:norains:2007年4月8号;
liswei:2008年2月20号.
  而且我的程序是引用了norains共享的Creg类代码才实现的,在这里谢谢norains了!

#17楼    回复  引用    

2008-07-29 13:39 by norains [未注册用户]
另一个事实是,我公开的那个CReg也不是我写的,也是从微软中拷贝出来,只不过修改了下代码格式和去掉了一些无用的功能。

之所以挑CReg出来说,只是看不惯文章中提到CReg的那种语气。一个微软公开的类,不仅弄得神神秘秘,还要往自己脸上贴金----当然我也不排除说者无意,听着有心,以及我带有偏见的原因所在。

#18楼 [楼主]   回复  引用  查看    

2008-07-29 15:05 by Walzer      
@norains

这篇文章是我徒弟写的,文章开头有标注,末尾有我的评点.至于他学习过程中可能参考了norains你的文章,并且不加声明地直接当做自己的文字发表出来,这个我回头会好好教育一下.让他出来道歉.

至于CReg, 我用的是微软PUBLIC目录下的, 这点在文章首发时就有加注释,回复里也有提到. norains抓住这个问题不放,火气太大了吧, 消消火. 注意看一下这文字,
原文是"上面用到的CReg是一个对注册表操作的类,是我们小组用的一个基类(Walzer注:在WINCE500目录下搜索CReg可以找到, 其实微软的人也很懒)。"
首先,这是我们组"用的一个基类",而没有写成我们组"写的一个基类",并且我首次发布时就注释了"在WINCE500目录下可以搜到".

就文中抄袭一事, 我再次向norains道歉, 我已在这文章头上加进去说明. 一会儿让徒弟出来道歉.

#19楼    回复  引用    

2008-07-29 16:10 by liswei [未注册用户]
@norains

关于此事,确实我在wince5.0上调试声音的测试程序中,确实有参考过norains 关于“wince音量设置”这篇blog,然而,对自己的声音调试测试是通过我自己真实的调试过程写出来的,文章也包含了我的一些做法,只是写blog的时候,本来都是写wince 音量调节的,又是微软的那么一套东西,写出来的肯定会有类似的(有参考,但肯定不是转载)。
但关于norains说我的文章有参考他的,这个我不否认,在此我也向norains表示道歉。但我想能帮助有需要的人解决他们的问题,这不正是我们写技术型blog的精神所在。

#20楼    回复  引用    

2008-07-29 19:00 by norains [未注册用户]
to Walzer:
关于CReg类,说实话,从另一个角度来看,原文"上面用到的CReg是一个对注册表操作的类,是我们小组用的一个基类(Walzer注:在WINCE500目录下搜索CReg可以找到, 其实微软的人也很懒)。"并无不妥,就像我之前的留言所说的,我觉得不爽的原因更多是出在自己身上---->偏见,迁怒。不同的心境之下看同样的文字,一定会有不一样的想法。So,关于CReg,对自己之前的言行做个道歉。


to liswei:
参考没关系,大量参考乃至复制黏贴也没关系,但至少给我留个名吧,好歹我写个豆腐块以及找出原因也花了不少时间吧?以黑话来说,死也至少给我留个全尸吧? :-)


PS:
删掉就不必要了,就留着了。换句话说,这也不是什么大不了的事,不必小题大做。因为不通知我,直接转载文章的网站和个人太多了。
之所以两天盯着这文章,完全是因为这两天心情不佳,然后看到这没标明的文章,火气太大。算起来,这算是医学上所不齿的迁怒了。
文章还是留着,但文章前面的红色的字过于扎眼,能不能将那红色字去掉?我唯一的要求是,在文章末尾提一下,本文有部分参考《WinCE系统音量的设置》该文即可。不知道两位意下如何?
谢谢!

#21楼    回复  引用    

2008-07-29 19:39 by norains [未注册用户]
顺便,给文章挑一下刺。(先声明一下,以下讨论尽量不带任何个人色彩,只是从技术角度上讨论)

原文:
“通过waveOutSetVolume()这个API,我们可以很容易的更改系统设备的音量,但这个时候,如果你去查看注册表的Volume的键值是没有变化的,因为它只修改了设备的音量,变化还没有这么快到达注册表。但你可以到“控制面板”中的“音量与声音”打开一下,注册表的值也随之改变。(反之,通过对注册表的单独操作对具体音量是起不到作用的)”
waveOutSetVolume是一个不涉及到注册表的API,所以并不是“变化还没有这么快到达注册表”。
也就是说,调节主音量基本上有两个方法:
1. waveOutSetVolume--> Write Registry
2. Write Registry --> AudioUpdateFromRegistry
PS:微软的控制面板用的是第二种方法。


原文:
“第一种方法比较不稳定,因为有一些人的sdk中没有这个pwinuser.h文件,所以程序找不到。”
印象中,SDK无论如何选择组件似乎都不可能包含该文件(有待确认)。之所以不采用包含头文件的最合适理由是:避免调用地址出错。
首先,如果我们需要采用.h文件方式,那么我们还需要相应的.lib。这个lib包含了函数入口地址,而这个lib必须要和将要调用的DLL地址一致。在此先说明一下,DLL的函数地址是可以随着编译参数的不同而不同的,简单地说,release和debug的DLL的函数地址是完全不同的。如果你的DLL是RELEASE,那么你的lib也必须要用Release。再一次也就是说,如果DLL变更了,那么APPLICATION也必须变更。


再是,就是个人意见了,只是说说而已。将这种调用DLL函数的方式称为“暴力调用dll”似乎不妥,因为在C++中,这是一个标准的调用DLL函数的方法。相对于C#的DLL调用而言,确实是显得麻烦些了。

#22楼 [楼主]   回复  引用  查看    

2008-07-29 22:37 by Walzer      
呵呵,大家言合了就好.
其实也没什么,只是些微软的游戏规则而已. 咱们在这里吵, 微软的人估计都在偷笑了,哈哈.

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-07-29 22:25 编辑过