レジストリの操作について。

解決


きっちょむ  2002-11-19 07:02:58  No: 76377

最近VBをはじめた者ですが、宜しければ教えてください。

windows API のRegSetValueExを使いたく、
HP上にあるサンプルソースをダウンロードして、実行しましたが、

    '値を設定する
    Ret = RegSetValueEx(nHandle, Text1.Text, 0, REG_SZ, Text2.Text, nLeng)
の部分でretに5が設定され、レジストリ登録が出来ません。
ちなみにレジストリキーの設定(RegCreateKeyEx)はうまく設定できました。
家のOSはXPになります。
単に実行だけではなく、事前に他の処理が必要なのでしょうか?

よろしくお願いします。


oku  URL  2002-11-19 09:03:58  No: 76378

はい、事前に(前後に)準備が要ります。
レジのオープン&クローズ処理が必要です。
INIファイルで十分なので、自分もあまりレジを触ったことないので、
間違ってたらすいません。

'RegOpenKeyEx=>レジストリのキーを開く

'<引数>
'hKey:         Rootキー(定数HKEY××参照)
'lpSubKey:      Subキー
'ulOptions:     常に0
'samDesired:    常に1
'phkResult:     開いたキーのハンドルを受取る変数

'@戻り値@
'正常終了のとき ERROR_SUCCESS

Private 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

'RegCloseKey=>レジストリのハンドルを閉じる

'<引数>
'hKey: レジストリのハンドル

'@戻り値@
'なし

Private Declare Function RegCloseKey Lib "ADVAPI32" (ByVal hKey As Long) As Long

'RegSetValueEx=>レジストリの値名、値を設定する

'<引数>
'hKey:RegOpenKeyExで取得したハンドル
'lpValueName:値名
'Reserved:常に0
'dwType:定数(REG_××参照)
'lpData:値を示す文字列
'cbData:値を示す文字列の文字数
'
'<戻り値>
'正常終了のとき ERROR_SUCCESS

Private Declare Function RegSetValueEx Lib "advapi32.dll" Alias "RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, ByVal Reserved As Long, ByVal dwType As Long, ByVal lpData As Any, ByVal cbData As Long) As Long

'<注>RegSetValueExの引数「lpData」の前にByValをつけています。
'ほかにもやり方がありますが、ByValを書くだけなのでこの方法をとりました。
'--->REG_DWORDを使う時はByValを消さないと使用できません(REG_DWORDは使わないと思いますが・・・)

'ルートキー
Const HKEY_CLASSES_ROOT = &H80000000
Const HKEY_CURRENT_CONFIG = &H80000005
Const HKEY_CURRENT_USER = &H80000001
Const HKEY_DYN_DATA = &H80000006
Const HKEY_LOCAL_MACHINE = &H80000002
Const HKEY_PERFORMANCE_DATA = &H80000004
Const HKEY_USERS = &H80000003

Const ERROR_SUCCESS = 0

'値のタイプ
Const REG_SZ = 1
'Const REG_DWORD = 4

Private Sub Command1_Click()

    Dim Ret         As Long
    Dim Rootkey     As String
    Dim Subkey      As String
    Dim nHandle     As Long
    Dim nLeng       As Long

    Rootkey = HKEY_CURRENT_USER
    Subkey = "Software"

    nLeng = Len(Text2.Text)

    'ハンドル確保
    Ret = RegOpenKeyEx(Rootkey, Subkey, 0, 1, nHandle)

    '値を設定する
    Ret = RegSetValueEx(nHandle, Text1.Text, 0, REG_SZ, Text2.Text, nLeng)

    'ハンドルを閉じる
    Call RegCloseKey(nHandle)

    'エラーの確認
    If Ret = ERROR_SUCCESS Then
        MsgBox "正常に設定しました"
    Else
        MsgBox "正常に設定できませんでした"
    End If
End Sub

こんな感じでどうでしょうか?


きっちょむ  2002-11-19 10:49:48  No: 76379

okuさんレスありがとうございます。
何回かソース見直しましたが、問題なさそうでした。
定数の部分は省きますが、ソースは以下の感じになります。

Private Function set_key() As String
    Dim Ret As Long
    Dim nHandle As Long
    Dim nLeng As Long
    Dim atai As String
    Dim SA As SECURITY_ATTRIBUTES
    Dim Disposition As Long
 
    Const Rootkey = HKEY_LOCAL_MACHINE
    Const SubKey = "Software\\abcd\\efg"

    atai = "abccc"
    nLeng = Len(atai)

    call RegCreateKeyEx(Rootkey, SubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, SA, nHandle ,Disposition)

    Call RegCloseKey(nHandle)

    If Disposition = REG_OPENED_EXISTING_KEY Then
        set_key = "同じキーが存在するので作成できませんでした"
        Exit Function
    End If

    Ret = RegOpenKeyEx(Rootkey, SubKey, 0, 1, nHandle)

    Ret = RegSetValueEx(nHandle, "abcdef",0, REG_SZ, atai, nLeng)

    Call RegCloseKey(nHandle)

    If Ret = ERROR_SUCCESS Then
        set_key = "正常に設定しました"
    Else
        set_key = "正常に設定できませんでした"
    End If
end function

やはり、RegSetValueExのコール部のretに5が代入されてうまく出来ませんでした。。。
ソースのおかしなところがあればご教授お願いします。


YuO  2002-11-19 12:16:34  No: 76380

> RegCreateKeyEx(Rootkey, SubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, SA, nHandle ,Disposition)

KEY_CREATE_SUB_KEYをKEY_ALL_ACCESSにすれば,
そのままRegSetValueExへ渡せますよ。
#正確には,KEY_SET_VALUE。

あと,SAは不要。ByVal 0&を渡しておけばよいです。
#細かいセキュリティ設定するなら別ですが。

> Ret = RegOpenKeyEx(Rootkey, SubKey, 0, 1, nHandle)

これは,定数を使うと,
Ret = RegOpenKeyEx(Rootkey, Subkey, 0, KEY_QUERY_VALUE, nHandle)
ですから,このnHandleは読み込み専用です。
よって,RegSetValueExで書き込めないのは当然です。

RegOpenKeyExを使うなら,
Ret = RegOpenKeyEx(Rootkey, Subkey, 0, KEY_ALL_ACCESS, nHandle)
のように必要なアクセス手段を指定する必要があります。


oku  URL  2002-11-20 05:49:40  No: 76381

嘘ついてたみたいですね。申し訳m(__)m
恥ずかしい(^_^;)


きっちょむ  2002-11-20 06:13:17  No: 76382

いえいえ、okuさんの言うとおりに変更しましたらうまくいきましたよ。
KEY_ALL_ACCESSは以下のように求めました。
Public Const READ_CONTROL = &H20000
Public Const KEY_QUERY_VALUE = &H1
Public Const KEY_SET_VALUE = &H2
Public Const KEY_CREATE_SUB_KEY = &H4
Public Const KEY_ENUMERATE_SUB_KEYS = &H8
Public Const KEY_NOTIFY = &H10
Public Const KEY_CREATE_LINK = &H20
Public Const KEY_ALL_ACCESS = KEY_QUERY_VALUE + KEY_SET_VALUE + KEY_CREATE_SUB_KEY + KEY_ENUMERATE_SUB_KEYS + KEY_NOTIFY + KEY_CREATE_LINK + READ_CONTROL

あと、質問ついでですが、REG_SZのデータはセット及び取得ができますが、
REG_DWORDは設定のみ可能で、取得が出来ません(強制終了)。
申し訳ありませんが、知恵をお貸し下さい。

    'キーをオープンしてハンドルを得る
    Call RegOpenKeyEx(ROOTKEY, SUBKEY, 0, KEY_ALL_ACCESS, nHandle)
    key = 0
    'HensuはRegOpenKeyExで開いたキーのハンドル
    Call RegQueryValueExstr(nHandle, key_name, 0, REG_DWORD, key, Len(key))

    'ハンドルを閉じる
    Call RegCloseKey(nHandle)


きっちょむ  2002-11-20 06:14:45  No: 76383

すみません、okuさんとYuOさんと混合させてしまいました。
失礼しました。


YuO  2002-11-20 07:59:54  No: 76384

RegQueryValueExの宣言は,
LONG WINAPI RegQueryValueEx(HKEY hKey, LPTSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
です。
これをVBの宣言に直すと,
Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" (
    ByVal hKey As Long, ByVal strValueName As String, ByRef lpReserved As Long,
    ByRef lngType As Long, lpData As Any, ByRef cbData As Long) As Long
となります。
#冗長ですが,ByRefを付けました。
つまり,種別は取得されるものであって,指定するものではないです。
よって,

Dim lngType As Long, cbData As Long
Dim Result As Long

cbData = Len(key)
Result = RegQueryValueEx(nHandle, key_name, ByVal 0&, lngType, key, cbData)
If Result <> ERROR_SUCCESS Then
    Rem エラー時の処理
End If

のような形式になります。


YuO  2002-11-20 08:01:55  No: 76385

そうそう,フラグを+で足すのはやめた方がよいです。
Const KEY_ALL_ACCESS As Long = KEY_QUERY_VALUE Or KEY_SET_VALUE Or ...
としましょう。


きっちょむ  2002-11-20 08:46:29  No: 76386

度々申し訳ありません。
何度も確認を行いましたが、未だにうまくいきませんでした。
宜しければもう少しお力添えをお願いします。

Public 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
Public Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" (ByVal hKey As Long, ByVal strValueName As String, ByRef lpReserved As Long, ByVal lngType As Long, lpData As Any, ByRef cbData As Long) As Long

Public Const REG_DWORD = 4
Public Const KEY_QUERY_VALUE = &H1
Public Const HKEY_LOCAL_MACHINE = &H80000002

Const ROOTKEY = HKEY_LOCAL_MACHINE
Const SUBKEY = "Software\\ABCD\\EFG"

Private Function get_reg(key_name As String) As String
    Dim key As Long
    Dim nHandle As Long
    Dim length  As Long
    Dim Ret As Long
    
    length = Len(key)

    'キーをオープンしてハンドルを得る
    Ret = RegOpenKeyEx(ROOTKEY, SUBKEY, 0, KEY_QUERY_VALUE, nHandle)
    key = 0
    'HensuはRegOpenKeyExで開いたキーのハンドル
    Ret = RegQueryValueEx(nHandle, key_name, 0, REG_DWORD, key, length)

    'ハンドルを閉じる
    Call RegCloseKey(nHandle)

    get_reg = key
End Function

このソースでRegQueryValueExが87を返します。(RegOpenKeyExは0を)
レジストリには、値が既に登録されており、regeditにて確認もしております。
申し訳ありませんが、よろしくお願いします。


きっちょむ  2002-11-20 08:48:05  No: 76387

Private Function get_reg(key_name As String) As String

Private Function get_reg(key_name As String) As Long
ですね。すみません。
しかし、今回の問題とは関係なさそうです。


きっちょむ  2002-11-20 09:23:18  No: 76388

Public Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" _
(ByVal hKey As Long, ByVal strValueName As String, ByVal lpReserved As Long, _
    ByRef lngType As Long, lpData As Any, ByRef cbData As Long) As Long

いろいろ試した結果、
この宣言方法で上手く出来るようになりました。
いろいろご迷惑をおかけしましたが、凄く充実感に溢れています。
ご指導のありがとうございました。


YuO  2002-11-20 11:27:13  No: 76389

解決が付いていますが根本的なところがまったくわかっていないようなので書きます。

まず,RegQueryValueExの引数は,順に,
・HKEY hKey (in)
目的の値が存在するキーのハンドル。入力。
・LPCTSTR lpValueName (in)
目的の値の名前。入力。
#ヘルプの誤植のことを忘れていたので,前回LPTSTRとしていました。
・LPDWORD lpReserved
予約された引数。NULLを渡すこと。
#VBだと,ByRefでByVal 0&を渡すことで対応。
・LPDWORD lpType (out)
値の種類を受け取る変数へのポインタ。出力。
・LPBYTE lpData (out)
値のデータを受け取るバイト列の先頭へのポインタ。出力。
・LPDWORD lpcbData (in/out)
入力としてlpDataのバッファサイズを渡し,
実際に使ったデータを出力として受けるための変数へのポインタ。入出力。

となっています。
私が書いたコードをよく読んでください。
REG_DWORDを指定しているようですが,全く意味がないです。

ちなみに,
> このソースでRegQueryValueExが87を返します。
は,
>87 : ERROR_INVALID_PARAMETER
>パラメータに誤りがあります。
という内容のエラーです。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加