一、注冊表編程詳解
Windows 注冊表中包含了系統配置、機器硬件配置、 Win32 應用程序和用戶的其他配置信息。許多高級一些的功能都要通過對注冊表的操作來實現。在 WinAPI 中提供了 RegCgreateKey() 、 RegOpenKey() 、 RegQueryValue() 等函數操作注冊表,但是用這些函數來操作注冊表使用起來非常麻煩。而利用 C ++ Builder 的 TREGISTRY 類,我們則可以輕松實現對注冊表的操作。下面我先介紹一下 TRegistry 類使用方法。
1. 使用前的准備工作:
首先必須在程序開始處包含定義類模塊的頭文件:
#include -registry.hpp-
其次在全程變量(即所有函數之前)創建類的一個實例(對象):
TRegistry * 實例名 =new TRegistry();
注意:我們不能用直接聲明的方法生成 TREGISTRY 的實例,這與 VC ++中用 HKEY 直接生成實例的方法不同。必須采用 new 關鍵字生成 TREGISTRY 類的實例,然後將指針傳遞給聲名的變量。采用這個方式聲明後,實例的 RootKey 屬性指向 HKEY_CURRENT_USER 根鍵,即默認操作是針對 HKEY_CURRENT_USER 進行的。
2. 常用屬性和方法介紹:
(1) 當前根鍵屬性( RootKey ):
RootKey 屬性定義了注冊表類實例當前根鍵,默認的是 HKEY_LOCAL_USER , 如果我們需要在其它根鍵下對注冊表進行操作,可以修改 RootKey 屬性:
MyReg->RootKey= 根鍵名 ;
BCB 中對注冊表根鍵共有以下幾個定義: HKEY_CURRENT_USER 、 HKEY_CLASSES_ROOT 、 HKEY_LOCAL_MACHINE 、 HKEY_USERS 、 HKEY_CURRENT_CONFIG 、 HKEY_DYN_DATA 、 HKEY_USERS 。分別對應注冊表中相應的主鍵。(該屬性為 int 型)
(2)當前鍵值的文本描述屬性( CurrentPath ):
CurrentPath 屬性定義了注冊表當前鍵值的文本描述,如\HKEY_CURRENT_USER\Software\Borland 的 CurrentPath=-Software\Borland- ,而 RootKey=HKEY_CURRENT_USER (該屬性為 AnsiString 型)。
(3)是否使修改後的值立即反映到注冊表中( LazyWrite ):
這個屬性的作用是決定是否在執行寫操作之後立即將所做的改動反映到實際的注冊表中。這個屬性的值在注冊表對象構造時初始化為 true ,即不立即將所做的改動反映到實際的注冊表中,而是在執行 CloseKey() 函數之後重寫注冊表,這樣可以提高系統性能。但是,如果我們需要將修改立即反映到注冊表(這在許多場合是必要的),則應當首先將 LazyWrite 屬性設置為 false ,然後執行修改操作。
(4) 建立主鍵函數:
bool __fastcall CreateKey( 主鍵名 );
如果主鍵已經存在,就覆蓋原主鍵。如在當前主鍵下建立“ MyReg ”主鍵,可用“ CreateKey(-MyReg-) ”,而“ CreateKey(-\\MyReg-) ” 則在當前根鍵下建立主鍵 MyKey 。
(5) 刪除主鍵函數:
bool __fastcall DeleteKey( 主鍵名 );
如果參數為空字符串,則刪除當前鍵值 。
(6) 打開主鍵函數 :
bool __fastcall OpenKey( 主鍵名,參數 );
此函數將定位到一個具體的主鍵位置,隨後的操作(建立鍵值、刪除鍵值以及在當前位置建立主鍵、刪除主鍵)將以此主鍵為當前主鍵。參數為 True 則當主鍵不存在將建立這個主鍵,如果為 false 則不建立主鍵。
(7) 讀取當前主鍵下 String 型的鍵值函數:
AnsiString __fastcall ReadString( 鍵值名 );
如: Edit1->Text=MyReg->ReadString(-MyString-);
將讀取鍵值 MyString 的內容到文本框 Edit1 中。 同此函數類似的還有 ReadBool() 、 ReadInteger() 、 ReadFloat() 、 ReadDateTome() 、 ReadBinaryData() 等,用來讀出不同類型的鍵值。
(8) 在當前主鍵中寫入 String 型鍵值函數:
void __fastcall WriteString( 鍵值名,數據 );
如果是一個新鍵值名,那麼相當於新建一個鍵值;如果是已有的鍵值,那麼就是修改鍵值的數據。
如: WriteString(- 我的串 -,- 內容 -); 其它類型的鍵值(二進制值、 Dword 值)的讀取和寫入函數如 WriteInteger 、 WriteBool() 、 WriteFloat() 、 WriteDateTome() 、 WriteBinaryData() 等用法與上述類似。
(9) 判斷鍵值或主鍵是否存在的函數:
bool __fastcall ValueExists( 鍵值名 );
這個方法判斷當前鍵下是否存在指定的數據項,如果存在返回 true ,否則返回 false 。
bool __fastcall KeyExists( 主鍵名 );
這個方法判斷一個鍵是否存在,如果存在返回 true ,否則返回 false 。
(10)從文件讀入鍵值函數:
LoadKey( 鍵值名 , 文件名 ) ;
(11)一個鍵值保存到文件函數:
SaveKey( 鍵值名 , 文件名 ) ;
(12) 關閉鍵值函數:
void __fastcall CloseKey(void);
在注冊表使用完畢後,應當及時調用 CloseKey() 成員函數關閉注冊表,並調用 delete 方法將用 new 申請的內存空間釋放。
(13)當前主鍵下子鍵值的獲取函數:
void __fastcall GetKeyNames(Classes::TStrings * Strings) ;
我們可以用該成員函數得到當前主鍵下所有子鍵的名稱,用 GetKeyInfo 得到更加詳細的信息。必須指出,雖然 GetKeyNames() 的說明成 void __fastcall GetKeyNames(Classes::TStrings * Strings) ,也就是說,它的參數類型是 TString ,但是我們並不能首先聲明一個 TString 類的實例,然後將它作為參數用於 GetKeyNames() 。這主要是由於 TStrings 類含有抽象成分。我們的解決方法是采用 TStrings 類的派生類 TStringList 來代替 TStrings 聲明一個實例,並作為參數用於 GetKeyNames() 函數。
在獲得子鍵的名稱後,我們就可以利用有關函數進一步確定詳細信息。如用我們可以用 GetValueNames() 結合 Read() 和 Write() 獲得主鍵的值的詳細信息。請看下面實例,這個例子的功能是將“ \Software\MyInfo”主鍵下的所有子鍵名稱顯示在 ComboBox1 中:
# include
…………
Tregistry * curReg=new TRegistry () ;
curReg - >OpenKey( “ Software\\MyInfo-,true);
KeyNames=new TStringList();// 注意 TstirngList 類的聲明方法!
curReg - >GetKeyNames(KeyNames); for(int i=0;iCount;i ++ ) ComboBox1 - >Items - >Add(KeyNames - >Strings[i]);
curReg - >CloseKey();
delete KeyNames;
3 使用 TRegistry 的一般步驟
一般來說,有以下四步操作:
1) 建立 TRegistry 類。 2) 利用 OpenKey() 方法打開一個鍵值。 3) 用 ReadType() 和 WriteType() 讀寫鍵值。 4) 調用 CloseKey ()關閉一個鍵值,最後調用 delete 方法將用 new 申請的內存空間釋放。
二、應用實例1
下面我們通過一個示例程序演示了對注冊表的常見操作,包括打開主鍵、讀取不同類型的鍵值、刪除鍵值或主鍵等。“每次啟動電腦自動運行”復選框則實現的作用類似 Win 95 的 Welcome.exe 程序的功能。
首先在窗體添加 Edit1 、 Label1 、 label 2 (用於顯示運行次數)、 Button1 、 CheckBox1 ( Caption= “每次啟動電腦自動運行”)等幾個控件,然後添加以下源代碼。生成可執行文件後,改名為 MyReg.EXE 拷貝到 C: 盤根目錄下執行即可。
源代碼:
//--------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include -registry.hpp- // 包含頭文件
#include -Unit1.h-
//--------------------------------------------
#pragma package(smart_init)
#pragma resource -*.dfm-
TForm1 *Form1;
TRegistry *MyReg=new TRegistry();// 建立實例
//--------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{}
//--------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{MyReg->RootKey=HKEY_CURRENT_USER;
if((MyReg->OpenKey(-\\software\\MyReg-,false))==false)
{MessageBox(NULL,- 感謝第一次使用本軟件 !.-,- 歡迎 !-,IDOK);
MyReg->CreateKey(-\\software\\MyReg-);
MyReg->OpenKey(-\\software\\MyReg-,true);
MyReg->WriteInteger(-Number-,0);
MyReg->WriteString(-The String-,Edit1->Text);
}// 檢測有無注冊表項 , 沒有則建立
int num=MyReg->ReadInteger(-Number-);
num++;
MyReg->WriteInteger(-Number-,num);// 使用次數 +1 並寫入注冊表
Label2->Caption=IntToStr(num);
Edit1->Text=MyReg->ReadString(-The String-);
MyReg->CloseKey();
MyReg->RootKey=HKEY_LOCAL_MACHINE;
MyReg->OpenKey(-\\software\\Microsoft\\windows\\CurrentVersion\\Run-,false);
CheckBox1->Checked=MyReg->ValueExists(-AutoShow-);
MyReg->CloseKey();// 根據是否自動運行設定 CheckBox 狀態
}
//--------------------------------------------
void __fastcall TForm1::Edit1Change(TObject *Sender)
{MyReg->RootKey=HKEY_CURRENT_USER;
MyReg->OpenKey(-\\software\\MyReg-,false);
MyReg->WriteString(-The String-,Edit1->Text);
MyReg->CloseKey();//Edit1 改變寫入注冊表
}
//--------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{MyReg->RootKey=HKEY_LOCAL_MACHINE;
MyReg->OpenKey(-\\software\\Microsoft\\windows\\CurrentVersion\\Run-,false);
if(CheckBox1->Checked)
MyReg->WriteString(-AutoShow-,-c:\\MyReg.EXE-);
else MyReg->DeleteValue(-AutoShow-);
MyReg->CloseKey();// 如果 CheckBox 選中則自動運行 , 否則刪除自動運行鍵值
delete MyReg;
}
//--------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)// 單擊 Button1 刪除注冊表項
{MyReg->RootKey=HKEY_LOCAL_MACHINE;
MyReg->OpenKey(-\\software\\Microsoft\\windows\\CurrentVersion\\Run-,false);
MyReg->DeleteValue(-AutoShow-);
MyReg->CloseKey();//* 刪除自動運行鍵值
MyReg->RootKey=HKEY_CURRENT_USER;
MyReg->DeleteKey(-\\software\\MyReg-);// 刪除注冊表項
}
三、注冊表編程實例2—— 編寫輸入法調序器
通常我們使用輸入法時,要按下Ctrl+空格鍵多次才能找到自己所熟悉的輸入法,那麼我們能不能把自己最常用的輸入法調到英文輸入法後面呢?(即只按一下Ctrl+空格即可調出自己使用的輸入法)筆者經過研究,終於設計出了一個輸入法調序器。它可以把當前系統中的所有輸入法全部列出來,並可自由調整輸入法順序。下面筆者就把實現方法介紹給大家。
程序實現原理:
我們知道在注冊表HKEY_CURRENT_USER\keyboard layout\preload下有子鍵1、2、3、4、5(這就是輸入法的順序),每個子鍵的缺省鍵值即為標識該輸入法的串值,如串值00000409對應的是英文輸入法,串值E0040804對應的是智能ABC輸入法。如果想知道每一個串值對應什麼輸入法,我們可以在HKEY_lOCAL_MACHINE\System\CurrentControlSet\Control\Keyboard Layouts之下找到。知道了輸入法的存放位置及順序關系後,我們可以利用程序操作注冊表把代表輸入法順序的串值進行相應移動,即可實現我們的目的了。
具體實現步驟:
1、新建一工程文件,在窗體上放入一個ListBox組件、三個BitBtn組件和一個Label組件。
2、在窗體的單元文件中定義全局變量如下:
AnsiString *imeStr,temStr;
TRegistry *Reg1,*Reg2;//注冊表對象
TRegKeyInfo keyInfo;//主鍵信息變量
並在單元文件前部增加包含#include <Registry.hpp>
3、在窗體的OnCreate事件過程中輸入如下代碼
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Reg1=new TRegistry;//創建注冊表對象
Reg2=new TRegistry;
Reg1->RootKey=HKEY_CURRENT_USER;//定位注冊表根鍵
Reg2->RootKey=HKEY_LOCAL_MACHINE;
if(Reg1->OpenKey("\\keyboard layout\\preload\\",false)==true)
Reg1->GetKeyInfo(keyInfo);//取得指定主鍵信息
ListBox1->Items->Clear();
imeStr=new AnsiString[keyInfo.NumSubKeys];//動態創建數組
for(int i=0;i<keyInfo.NumSubKeys;i++)
{
if(Reg1->OpenKey("\\keyboard layout\\preload\\"+IntToStr(i+1),false)==true)
imeStr[i]=Reg1->ReadString("");//取得輸入法串值
if(Reg2->OpenKey("\\System\\CurrentControlSet\\Control\\Keyboard Layouts\\"+imeStr[i]+"\\",false)==true)
ListBox1->Items->Add(Reg2->ReadString("layout text"));//顯示輸入法名稱
}
Reg1->CloseKey();
Reg2->CloseKey();
delete Reg2;
}
4、在BitBtr1(上移按鈕)的OnClick事件中加入如下代碼
void __fastcall TForm1::BitBtn1Click(TObject *Sender)
{
int i=ListBox1->ItemIndex;//當前選擇的行號
if (i>0)
{
ListBox1->Items->Exchange(i,i-1);//交換列表框中內兩行的內容
temStr=imeStr[i];//對應串值也交換
imeStr[i]=imeStr[i-1];
imeStr[i-1]=temStr;
}
}
5、類似地,在BitBun2(下移)的OnClick事件中加入如下代碼
void __fastcall TForm1::BitBtn2Click(TObject *Sender)
{
int i=ListBox1->ItemIndex;//當前選擇的行號
if (i<ListBox1->Items->Count-1)
{
ListBox1->Items->Exchange(i,i+1);
temStr=imeStr[i];//對應串值也交換
imeStr[i]=imeStr[i+1];
imeStr[i+1]=temStr;
}
}
6、在BitBtn3(確認按鈕)的OnClick事件中加入如下代碼
void __fastcall TForm1::BitBtn3Click(TObject *Sender)
{
if((Application->MessageBox("確認更改輸入法順序嗎?","請確認",MB_OKCANCEL|MB_ICONWARNING))==ID_OK)
{
for(int i=0;i<keyInfo.NumSubKeys;i++)
{
Reg1->OpenKey("\\keyboard layout\\preload\\"+IntToStr(i+1),false);
Reg1->WriteString("",imeStr[i]);
}//給輸入法重新排序
Reg1->CloseKey();
delete Reg1;
delete imeStr;
if((Application->MessageBox("馬上要重新啟動計算機","重啟計算機",MB_OKCANCEL|MB_ICONWARNING))==ID_OK)
ExitWindowsEx(EWX_REBOOT,0);
}
Close();
}
以上程序在Windows 98、C++ builder6.0下調試通過。