HOWTO:使用登錄 API 來儲存與擷取設定值

文章翻譯 文章翻譯
文章編號: 145679 - 檢視此文章適用的產品。
本文曾發行於 CHT145679
全部展開 | 全部摺疊

在此頁中

結論

雖然 Visual Basic 含有 SaveSetting 與 GetSetting 函數,可以儲存與擷取登錄的資訊,但這些函數只能用於某特定區段的登錄,亦即 HKEY_CURRENT_USER 根目錄機碼的 [VB and VBA Program Settings]。

本文說明 32 位元 Windows API 函數的使用,您可以用這些函數來設定與擷取登錄中任何地方的登錄值。本文所提到的主題與函數可以歸納起來以設計 16 位元的登錄。

32 位元的 API 函數也包含對安全性的支援,但安全性的概論不是本文所要討論的範圍。

注意:SaveSetting 與 GetSetting 函數不是 VBA 函數庫的一部份,然而,下面的程式碼範例仍然適用於使用 VBA 的 32 位元應用程式。

其他相關資訊

一般登錄資訊



應用程式與 Windows 都是使用登錄來儲存組態設定資料。登錄是用來取代大量 INI 檔的解決方案,INI 檔用於 Windows 3.x 電腦,會慢慢漸增,而 OLE 也會大量使用 INI 檔。

登錄是以階層式的一系列機碼與值組織而成,類似樹狀結構。一開始有六個預先定義的根目錄機碼,其下的每一個機碼都可能含有與其關聯的子機碼與值。機碼具有組織性,並且是可命名的單元,會以檔案資料夾的樣子出現在 Windows「登錄編輯器」中。值是資料項目,會以文字項目方式出現在「登錄編輯器」視窗的右邊窗格中。機碼可以不具備任何關聯的值,但也可能會包含很多值。每一個值都有關聯的資料類型,兩個最常用的登錄資料類型是 REG_SZ,這是一種以 Null 結束的字串;以及 REG_DWORD,這是一種 32 位元的數字。

用來寫入或讀取登錄中某個位置的基本程序是相同的。若要參照任何特定機碼或值,您必須要有那個機碼的控制把手,一旦取得此控制把手,您就可以讀取、設定或列出 (列舉) 此控制把手所參照的機碼中的值與子機碼。

若指定登錄中的某位置,想要取得此機碼的控制把手,您必須從六個預先定義的機碼之一開始進行 (HKEY_CLASSES_ROOT、HKEY_CURRENT_USER、HKEY_LOCAL_MACHINE、HKEY_USERS、HKEY_CURRENT_CONFIG 與 HKEY_DYN_DATA),在登錄樹狀目錄中走動,直到找出所要的機碼為止。使用者的程式最常讀取與寫入的位置是 HKEY_CURRENT_USER 與 HKEY_LOCAL_MACHINE。如果您在搜尋的機碼早已存在,就可以對 RegOpenKey 或 RegOpenKeyEx 函數使用一系列呼叫。如果必須建立機碼,RegCreateKey 與 RegCreateKeyEx 函數就會去執行。

具有所需機碼的控制把手,就可以呼叫用來列出、設定與擷取資訊的函數。如果是具有 Ex 字尾的函數,則此函數只能用於 32 位元的平台。如果函數沒有此字尾,可能可以同時用於 16 位元與 32 位元版本的 Windows。請注意,並不是所有沒有加上「Ex」字尾的登錄函數都能用於 16 位元平台。只有在 16 位元函數的功能擴展後才會加上 Ex 字尾。全新的函數與專為 32 位元平台設計的函數都不會有 Ex 字尾。

RegSetValue 與 RegSetValueEx 函數可用來修改值的設定,而 RegQueryValue 與 RegQueryValueEx 則是用來擷取值的目前設定。沒有 Ex 字尾的 16 位元版本的 API 在這裡有很明顯的限制。如果使用 16 位元的 RegSetValue 函數,就無法替值命名,因為這樣,RegSetValue 就無法用來將每個機碼和多個值關聯在一起。此外,所有以 RegSetValue 寫入的值,其資料類型都是 REG_SZ。這些都是 16 位元登錄的先天限制,RegSetValueEx 可讓您建立多個值,並且其資料類型可以是任何可用的資料類型。

如何寫入某特定登錄位置



決定您的專案需要使用哪些函數之後,請從本文結尾的程式碼將相關宣告複製到基本模組中,其中包含的兩個 Visual Basic 程序 (SetValueEx 與 QueryValueEx) 是 RegSetValueEx 與 RegQueryValueEx API 函數的包裝函式,大大簡化了其用法。下面的附註利用了這些 Visual Basic 函數,然而,如果您想要的話,也可以自由的直接呼叫 API。

建立/修改機碼與值:

有了可用的宣告與程序,您就可以建立與開啟機碼,新增、修改與讀取值。下面三節內容將說明如何建立機碼、設定或修改值,以及查詢某個值。

建立新機碼:

建立新機碼如同使用下面程序一樣簡單。CreateNewKey 會取得要建立的機碼名稱,以及代表預先定義的機碼的那個常數 (那個您要在它下面建立機碼的預先定義的機碼)。對 RegCreateKeyEx 的呼叫並沒有善用允許的安全性機制,但可以修改成那樣。登錄安全性不是本文所要討論的範圍。
   Private Sub CreateNewKey (sNewKeyName As String, lPredefinedKey As Long)
       Dim hNewKey As Long         'handle to the new key
       Dim lRetVal As Long         'result of the RegCreateKeyEx function

       lRetVal = RegCreateKeyEx(lPredefinedKey, sNewKeyName, 0&, _
                 vbNullString, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, _
                 0&, hNewKey, lRetVal)
       RegCloseKey (hNewKey)
   End Sub

搭配此程序的呼叫是:
   CreateNewKey "TestKey", HKEY_LOCAL_MACHINE

這樣就會直接在 HKEY_LOCAL_MACHINE 下建立一個稱為 TestKey 的機碼。

若依下面方式呼叫 CreateNewKey:
      CreateNewKey "TestKey\SubKey1\SubKey2", HKEY_LOCAL_MACHINE

就會直接在 HKEY_CURRENT_USER 下建立三層巢狀機碼,以 TestKey 為開頭,建立在 TestKey 下面的是 SubKey1,建立在 SubKey2 下面的是 SubKey3。

設定/修改某個值:

您可以用下面簡短的程序來建立與設定某特定機碼的值。SetKeyValue 會取得和此值關聯的機碼、值的名稱、值的設定,以及值的類型 (SetValueEx 函數只支援 REG_SZ 與 REG_DWORD,但如果有需要也可以做修改)。替現有的 sValueName 設定新值會變更此值目前的設定。
   Private Sub SetKeyValue (sKeyName As String, sValueName As String, _
   vValueSetting As Variant, lValueType As Long)
       Dim lRetVal As Long         'result of the SetValueEx function
       Dim hKey As Long         'handle of open key

       'open the specified key
       lRetVal = RegOpenKeyEx(HKEY_CURRENT_USER, sKeyName, 0, _
                                 KEY_SET_VALUE, hKey)
       lRetVal = SetValueEx(hKey, sValueName, lValueType, vValueSetting)
       RegCloseKey (hKey)
   End Sub

呼叫如下:
   SetKeyValue "TestKey\SubKey1", "StringValue", "Hello", REG_SZ

這樣就會建立一個 REG_SZ 類型的值,稱為「StringValue」,其設定值是「Hello」。這個值會關聯到「TestKey」的機碼 SubKey1。

在此案例中,「TestKey」是 HKEY_CURRENT_USER 的子機碼,但我們可以經由變更對 RegOpenKeyEx 的呼叫來做修改,如果「TestKey\SubKey1」不存在,此呼叫就會失敗。若要避免發生此問題,請使用對 RegCreateKeyEx 的呼叫,不要使用對 RegOpenKeyEx 的呼叫。如果某特定機碼早已存在,RegCreateKeyEx 就會開啟此機碼。

查詢某個值:

下一個程序可以用來查明現有值的設定為何。QueryValue 會取得機碼名稱,以及和此機碼關聯的值的名稱,並顯示出包含相對應的值的訊息方塊。它會使用對下文所定義的 QueryValueEx 包裝函式的呼叫,此包裝函式只支援 REG_SZ 與 REG_DWORD 類型。
   Private Sub QueryValue (sKeyName As String, sValueName As String)
       Dim lRetVal As Long         'result of the API functions
       Dim hKey As Long         'handle of opened key
       Dim vValue As Variant      'setting of queried value

       lRetVal = RegOpenKeyEx(HKEY_CURRENT_USER, sKeyName, 0, _
   KEY_QUERY_VALUE, hKey)
       lRetVal = QueryValueEx(hKey, sValueName, vValue)
       MsgBox vValue
       RegCloseKey (hKey)
   End Sub

搭配此程序的呼叫是:
   QueryValue "TestKey\SubKey1", "StringValue"

這樣就會出現一個訊息方塊,顯示出「StringValue」這個值目前的設定,假設「TestKey\SubKey1」機碼中有「StringValue」。

如果您所查詢的值不存在,則 QueryValue 會傳回代號 2 的錯誤碼 - 'ERROR_BADKEY'。

其他注意事項:

上述範例全部是使用擴充的 32 位元版本的登錄函數,這些函數可讓每一個機碼與多個值關聯在一起。如上文所述,16 位元的 RegSetValue 與 RegQueryValue 會作用在和目前機碼相關聯的單一值 (只能是 REG_SZ 類型)。這些函數會在 32 位元的「登錄編輯器」中以 <NO NAME> 的名稱出現。若要設定、修改或查詢此種特殊的關聯值,您必須使用 16 位元的登錄函數。在 16 位元環境中讀取與寫入登錄比在 32 位元的環境中單純的多。都是依照相同的基本程序:開啟機碼,取得控制把手,然後使用此控制把手呼叫修改函數,但如果是多個關聯值或不同的值資料類型,就不須做其他考量。16 位元的應用程式可以使用 RegCreateKey、RegOpenKey、RegQueryValue、RegSetValue 與 RegCloseKey 函數的宣告來建立或修改機碼與值。

在某些情況下,機碼並不需要有任何相關聯的值,應用程式可能只需要知道某特定機碼或值是否存在,而不必管機碼的值的本質為何。如果是這樣的情況,就可以使用 RegEnumKey、RegEnumKeyEx 與 RegEnumValue 函數來判斷某特定機碼或值是否存在。有關這些函數的其他資訊,請參考 API Text Viewer 與/或 Windows API 參考資料。

API 函數與常數宣告



   Option Explicit

   Public Const REG_SZ As Long = 1
   Public Const REG_DWORD As Long = 4

   Public Const HKEY_CLASSES_ROOT = &H80000000
   Public Const HKEY_CURRENT_USER = &H80000001
   Public Const HKEY_LOCAL_MACHINE = &H80000002
   Public Const HKEY_USERS = &H80000003

   Public Const ERROR_NONE = 0
   Public Const ERROR_BADDB = 1
   Public Const ERROR_BADKEY = 2
   Public Const ERROR_CANTOPEN = 3
   Public Const ERROR_CANTREAD = 4
   Public Const ERROR_CANTWRITE = 5
   Public Const ERROR_OUTOFMEMORY = 6
   Public Const ERROR_ARENA_TRASHED = 7
   Public Const ERROR_ACCESS_DENIED = 8
   Public Const ERROR_INVALID_PARAMETERS = 87
   Public Const ERROR_NO_MORE_ITEMS = 259

   Public Const KEY_QUERY_VALUE = &H1
   Public Const KEY_SET_VALUE = &H2
   Public Const KEY_ALL_ACCESS = &H3F

   Public Const REG_OPTION_NON_VOLATILE = 0

   Declare Function RegCloseKey Lib "advapi32.dll" _
   (ByVal hKey As Long) As Long
   Declare Function RegCreateKeyEx Lib "advapi32.dll" Alias _
   "RegCreateKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, _
   ByVal Reserved As Long, ByVal lpClass As String, ByVal dwOptions _
   As Long, ByVal samDesired As Long, ByVal lpSecurityAttributes _
   As Long, phkResult As Long, lpdwDisposition As Long) As Long
   Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias _
   "RegOpenKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, _
   ByVal ulOptions As Long, ByVal samDesired As Long, phkResult As _
   Long) As Long
   Declare Function RegQueryValueExString Lib "advapi32.dll" Alias _
   "RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName As _
   String, ByVal lpReserved As Long, lpType As Long, ByVal lpData _
   As String, lpcbData As Long) As Long
   Declare Function RegQueryValueExLong Lib "advapi32.dll" Alias _
   "RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName As _
   String, ByVal lpReserved As Long, lpType As Long, lpData As _
   Long, lpcbData As Long) As Long
   Declare Function RegQueryValueExNULL Lib "advapi32.dll" Alias _
   "RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName As _
   String, ByVal lpReserved As Long, lpType As Long, ByVal lpData _
   As Long, lpcbData As Long) As Long
   Declare Function RegSetValueExString Lib "advapi32.dll" Alias _
   "RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, _
   ByVal Reserved As Long, ByVal dwType As Long, ByVal lpValue As _
   String, ByVal cbData As Long) As Long
   Declare Function RegSetValueExLong Lib "advapi32.dll" Alias _
   "RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, _
   ByVal Reserved As Long, ByVal dwType As Long, lpValue As Long, _
   ByVal cbData As Long) As Long

SetValueEx 與 QueryValueEx 包裝函式:
   Public Function SetValueEx(ByVal hKey As Long, sValueName As String, _
   lType As Long, vValue As Variant) As Long
       Dim lValue As Long
       Dim sValue As String
       Select Case lType
           Case REG_SZ
               sValue = vValue & Chr$(0)
               SetValueEx = RegSetValueExString(hKey, sValueName, 0&, _
                                              lType, sValue, Len(sValue))
           Case REG_DWORD
               lValue = vValue
               SetValueEx = RegSetValueExLong(hKey, sValueName, 0&, _
   lType, lValue, 4)
           End Select
   End Function

   Function QueryValueEx(ByVal lhKey As Long, ByVal szValueName As _
   String, vValue As Variant) As Long
       Dim cch As Long
       Dim lrc As Long
       Dim lType As Long
       Dim lValue As Long
       Dim sValue As String

       On Error GoTo QueryValueExError

       ' Determine the size and type of data to be read
       lrc = RegQueryValueExNULL(lhKey, szValueName, 0&, lType, 0&, cch)
       If lrc <> ERROR_NONE Then Error 5

       Select Case lType
           ' For strings
           Case REG_SZ:
               sValue = String(cch, 0)

   lrc = RegQueryValueExString(lhKey, szValueName, 0&, lType, _
   sValue, cch)
               If lrc = ERROR_NONE Then
                   vValue = Left$(sValue, cch-1)
               Else
                   vValue = Empty
               End If
           ' For DWORDS
           Case REG_DWORD:
   lrc = RegQueryValueExLong(lhKey, szValueName, 0&, lType, _
   lValue, cch)
               If lrc = ERROR_NONE Then vValue = lValue
           Case Else
               'all other data types not supported
               lrc = -1
       End Select

   QueryValueExExit:
       QueryValueEx = lrc
       Exit Function

   QueryValueExError:
       Resume QueryValueExExit
   End Function

?考

《Programming the Windows 95 User Interface》,第 10 章 -〈Using the Registry〉

若需有關函數的參考資料:任何有關 Win16 或 Win32 API 的手冊。

本文件是根據 Microsoft Knowledgebase 文件編號 Q145679 翻譯的. 若要參考原始英文文件內容, 請至以下網址:

http://support.microsoft.com/support/kb/articles/Q145/6/79.asp

屬性

文章編號: 145679 - 上次校閱: 2003年8月19日 - 版次: 1.1
這篇文章中的資訊適用於:
  • Microsoft Visual Basic 5.0 Professional Edition
  • Microsoft Visual Basic 6.0 Professional Edition
  • Microsoft Visual Basic 5.0 Enterprise Edition
  • Microsoft Visual Basic 6.0 Enterprise Edition
  • Microsoft Visual Basic 4.0 Standard Edition
  • Microsoft Visual Basic 4.0 Professional Edition
  • Microsoft Visual Basic 4.0 Professional Edition
  • Microsoft Visual Basic 4.0 16-bit Enterprise Edition
  • Microsoft Visual Basic 4.0 32-Bit Enterprise Edition
  • Microsoft Visual Basic for Applications 5.0
  • Microsoft Visual Basic for Applications 6.0
關鍵字:?
kbhowto kbvb500 kbvbp kbtophit kbvbp400 kbvbp500 kbgrpdsvbdb kbvbp600 kbcode kbnokeyword kbvba KB145679
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。

提供意見

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com