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