Windows CE 6.0有4个基本的注册表键值, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS,其它的都是这4个注册表的子键。我们以一个内建的串口驱动为例,它在注册表文件Platform.reg中的描述如下:
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/Serial]
"Prefix"="COM"
"Dll"="$(_TGTPLAT_PFX)_serial.dll"
"Flags"=dword:0
"Index"=dword:1
其中Prefix 和 Dll项是必不可少的,Index为设备序号,Prefix代表设备文件名前缀,与Index合用表示该设备的名称,该注册表子键的设备名称就是"COM1:",该名称可以用于CreateFile调用。Dll则是动态链接库名称。Flags为1表示系统启动时不加载,需要应用程序自己加载,为0表示该驱动在系统启动时加载。
有两种方法操作注册表。第一种方法,在%WinCE Dir%Public%Common%OAK%INC%目录下,文件Cregedit.h中,定义了一个类CRegistryEdit来封装了注册表的操作。还有一种方法是利用windows CE提供的API进行注册表项的操作。分述如下:
(1)利用系统提供的注册表类CRegistryEdit
类的定义在文件regedit.h中。在构建函数中,会取得当前注册表子键的HANDLE句柄。有3个构造函数,第一个是用全路径,调用hKey = OpenDeviceKey(TEXT("HKEY_LOCAL_MACHINE//Drivers//BuiltIn//Serial"))构造;第二个是如果已知其父注册表子键,调用RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("Drivers//BuiltIn//Serial"), 0,0,&hKey)。第三种方法是用RegCreateKeyEx()。
析构函数中,调用RegCloseKey(hKey)关闭掉对注册表子键的引用。读取注册表项可以使用GetRegValue方法,写入注册表项使用RegSetValueEx方法。其方法的实现也是通过windows CE API,具体可以参照下一个Section。
(2)利用windows CE API
RegCreateKeyEx是新建一个注册表项,如果该项已经存在,就直接打开获取句柄。正常使用时,为了获取一个注册表键值,先要调用RegOpenKeyEx。以上面内建串口驱动为例,RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("Drivers//BuiltIn//Serial"), 0, 0, &hKey ),其中hKey就是我们获取的该注册表子键的HANDLE句柄。接下来对注册表子键的操作就是通过hKey来实现。
有了hKey, 就可以对注册表子键的各个内容进行读写操作。如果要读出子键的Prefix,调用函数RegQueryValueEx(hKey, TEXT("Prefix"), NULL, &lpType, &lpData, &lpcbData), lpType, lpData为Prefix返回类型和值,该例中,lpType = REG_SZ,lpData = TEXT("COM")。相对应读操作,写操作是一个相反的过程,RegSetValueEx(hKey, TEXT("Prefix"), NULL, REG_SZ, PBYTE(TEXT("TST")), wcslen(TEXT("TST"))*2),其中要写入的项为Prefix项,类型为REG_SZ,值为TEXT("TST"),最后一个参数为写入值得SIZE in bytes。注意第二个参数,如果注册表中存在该项,则改写它的值。如果没有,则新建一个注册表项。
某些情况下,我们需要删除一个注册表项,只需调用RegDeleteKey(hKey, TEXT("Index"))就可以删除Index注册表项。要关闭一个注册表子键,只需要调用RegCloseKey(hKey)就可以完成。
(3)实例
在HKEY_CURRENT_USER根键下,创建MySoftWare//RegTest键,并在此键下写入某人的姓名跟作者年龄信息,数据类型分别为字符串类型和整数类型。
HKEY hOpenKey;
DWORD dwOpenStyle;
long lResult = 0;
LPCTSTR keyName = L"MySoftWare//RegTest"; //定义键名
lResult = RegCreateKeyEx(HKEY_CURRENT_USER,keyName,0,L"",
0,0,NULL,&hOpenKey,&dwOpenStyle); //打开或者新建指定的键
ASSERT(lResult == ERROR_SRCCESS);
LPCTSTR strKeyName = L"作者"; //写入键值,字符串类型
LPCTSTR strKeyValue = L"王二";
lResult = RegSetValueEx(hOpenKey,strKeyName,0,REG_SZ,(BYTE*)strKeyValue,wcslen(strKeyValue)*2);
ASSERT(lResult == ERROR_SRCCESS);
LPCTSTR dwKeyName = L"年龄"; //写入键值,整数类型
DWORD dwKeyValue = 25;
lResult = RegSetValueEx(hOpenKey,dwKeyName ,0,REG_SZ,(BYTE*)dwKeyValue,wcslen(dwKeyValue)*2);
ASSERT(lResult == ERROR_SRCCESS);
RegCloseKey(hOpenKey);
对应的如果要读取上述写进去的值,方式如下:
DWORD dwKeyValueType = 0;
TCHAR strKeyValue[500];
zeroMemory(strKeyValue,500*2);
dwKeyValueLength = 500*2;
lResult = RegQueryValueEx(hOpenKey,strKeyName,0,&dwKeyValueType ,(BYTE*)strKeyValue,&dwKeyValueLength );
(4)注册表监控函数RegistryNotifyCallback用来对注册表项进行监控,一旦发生变化就执行回调函数。比如我们在操作上层应用界面的控件时,它会直接反映到注册表上,那么底层的注册表监控回调函数就执行,从而控制到驱动做对应的动作。以下通过一个振动器马达的动态链接库来举例说明。
#define DEVICE_MIS_FILE_NAME L"MIS1:" //马达设备
HANDLE hMisc=NULL; //马达句柄
bool g_bScreenTapsEnable=false; //马达震动的使能和禁止
bool g_bExited=false; //控制线程退出
void StartVibrator() //开始震动
{
if(hMisc == NULL)
{
hMisc = CreateFile(DEVICE_MIS_FILE_NAME, 0, 0, NULL, 0, 0, NULL);
}
if(hMisc)
{
int iSetValue = 0;
DWORD dwBufSize = sizeof(int);
DWORD dwRetSize = 0;
iSetValue = 1; //震动,通过IOCTL来实现
if(DeviceIoControl(hMisc, IOCTL_MIS_IT_VIBRATOR,&iSetValue,dwBufSize, NULL,0, &dwRetSize,NULL))
{
RETAILMSG (0,(TEXT( "miccco_touch IOCTL_MIS_IT_VIBRATOR() success /r/n"));
}
else
{
RETAILMSG (0,(TEXT( "miccco_touch IOCTL_MIS_IT_VIBRATOR() failure/r/n")));
}
}
}
void StopVibrator() //停止震动
{
if(hMisc == NULL)
{
hMisc = CreateFile(DEVICE_MIS_FILE_NAME, 0, 0, NULL, 0, 0, NULL);
}
if(hMisc)
{
int iSetValue = 0;
DWORD dwBufSize = sizeof(int);
DWORD dwRetSize = 0;
iSetValue = 0; //关闭震动
if(DeviceIoControl(hMisc, IOCTL_MIS_IT_VIBRATOR,&iSetValue,dwBufSize, NULL,0, &dwRetSize,NULL))
{
RETAILMSG (1,(TEXT( "miccco_touch IOCTL_MIS_IT_VIBRATOR() success dwRetSize/r/n"));
}
else
{
RETAILMSG (1,(TEXT( "miccco_touch IOCTL_MIS_IT_VIBRATOR() failure/r/n")));
}
}
}
DWORD WINAPI DoTouchVibrateThreadPrc(LPVOID lpParameter) //DLLMain中创建的线程函数
{
CeSetThreadPriority(GetCurrentThread(),100); //设置线程优先级
while(1)
{
WaitForSingleObject(g_hVibratorEvent, INFINITE); //等待点击事件发生
if(g_bExited) //检测到DLL被挂起,则退出循环
break;
StartVibrator();
Sleep(g_dwTime); //马达震动时间
StopVibrator();
}
return 0;
}
static void ScreenTapsCallbackFunc(HREGNOTIFY hNotify, DWORD dwUserData, const PBYTE pData, const UINT cbData) //注册表监控函数的回调函数,用来对注册表的改变做相应处理
{
if(*pData==1)
{
g_bScreenTapsEnable=TRUE; //使能马达
}
else
{
g_bScreenTapsEnable=false; //禁止马达
}
}
BOOL DllMain(HANDLE hInstDll, DWORD dwReason, LPVOID lpvReserved) //DLL主函数
{
if ( dwReason == DLL_PROCESS_ATTACH )
{
HKEY hKey=NULL;
DWORD dwDisposition=0,dwValue;
DWORD dwSize=sizeof(DWORD);
if ((ERROR_SUCCESS==RegCreateKeyEx(HKEY_CURRENT_USER, _T("ControlPanel//TouchVibration"),0,NULL,0,0,NULL,&hKey,&dwDisposition))) //创建键值
{
if((dwDisposition==REG_CREATED_NEW_KEY)) //判断是新建的键值
{
dwValue=0;
g_bScreenTapsEnable=false; //初始化禁止马达
RegSetValueEx(hKey,_T("ScreenTaps"),0,REG_DWORD,(BYTE *)&dwValue,sizeof(DWORD));
}
else //如果是打开的已存在的键值
{
if(ERROR_SUCCESS==RegQueryValueEx(hKey,_T("ScreenTaps"),0,0,(UCHAR*)&(dwValue),&dwSize)&&dwValue==1) //根据注册表的值来使能或者禁止马达
{
g_bScreenTapsEnable=TRUE;
}
else
{
g_bScreenTapsEnable=false;
}
}
RegCloseKey(hKey);
}
if ((ERROR_SUCCESS==RegCreateKeyEx(HKEY_CURRENT_USER, _T("ControlPanel"),0,NULL,0,0,NULL,&hKey,&dwDisposition)))
{
RegistryNotifyCallback(hKey, _T("TouchVibration"),_T("ScreenTaps"),ScreenTapsCallbackFunc,0,
NULL,&g_hRegNotify_ScreenTaps); //注册对某些键值进行监控的函数
RegCloseKey(hKey);
}
g_bExited=false; //初始化退出标志
g_hVibratorEvent=CreateEvent(NULL, FALSE, FALSE, NULL);
if(g_hVibratorEvent)
{
CreateThread(NULL, 0, DoTouchVibrateThreadPrc, NULL, 0, NULL); //创建触发标志及线程
}
DisableThreadLibraryCalls((HMODULE) hInstDll); //禁止再加载DLL
}
if ( dwReason == DLL_PROCESS_DETACH )
{
if(g_hRegNotify_ScreenTaps)
{
RegistryCloseNotification(g_hRegNotify_ScreenTaps); //取消注册表监控
g_hRegNotify_ScreenTaps=NULL;
}
if(g_hVibratorEvent)
{
g_bExited=true; //使线程退出
CloseHandle(g_hVibratorEvent);
}
}
return(TRUE);
}
BOOL DoTouchVibrate(DWORD dwLength) //DLL的暴露函数
{
if(g_bScreenTapsEnable) //从注册表获得的消息来判断是否动作
{
ResetEvent(g_hVibratorEvent); //防止连续震动,在每次震动事件之前,清除掉之前的事件
dwLength>200?g_dwTime=200:g_dwTime=dwLength;
SetEvent(g_hVibratorEvent);
}
return(TRUE);
}
参考原文:http://developer.51cto.com/art/200907/133698.htm