Open6

Rust初心者がRustでWindowsレジストリを操作するまで

MikutoMikuto

クレートを追加したが、windows::Win32::System::Registry以下、そもそもWin32すらインポートできない状況が続いた。
調べてみると、ビルド時間を短縮するために使用するfeaturesフラグを選択し、条件付きコンパイルを行うようだ。
https://aquasoftware.net/blog/?p=2223
必要なfeaturesはwindows-docs-rsには書いておらず、以下のぺージで検索できる。
https://microsoft.github.io/windows-rs/features/#/0.59.0

今回は、Registry周りをいじりたいので、以下のようにした。

Cargo.toml
[dependencies.windows]
version = "0.59.*"
features = [
    "Win32_System_Registry",
]

無事赤線が消えた。ヤッター

MikutoMikuto

registry値読み取りに使用したwindowsクレートの関数はRegOpenKeyExARegQueryValueExA
(RegGetValueでもよかったっぽい)

こんなコードになった

read
use windows::{
    core::PCSTR,
    Win32::System::Registry::*,
    Win32::Foundation::ERROR_SUCCESS
};
use std::ffi::CString;

fn get_registry_val(subkey_puth:String, value_name:String) -> Option<String> {
    let hkey: HKEY = HKEY_CURRENT_USER;
    let subkey_cstring = CString::new(subkey_puth).unwrap();  // NULL 終端が必要
    let subkey = PCSTR(subkey_cstring.as_ptr() as _);
    let valuename_cstring = CString::new(value_name).unwrap();
    let valuename = PCSTR(valuename_cstring.as_ptr() as _);
    let mut buffer = [0u8; 256];
    let mut bufsize = buffer.len() as u32;

    unsafe {
        let mut hsubkey = HKEY::default();
        let open_result = RegOpenKeyExA(hkey, subkey, Some(0), KEY_READ, &mut hsubkey);
        if open_result == ERROR_SUCCESS {
            let query_result = RegQueryValueExA(hsubkey, valuename, None, None, Some(buffer.as_mut_ptr()), Some(&mut bufsize));
            if query_result == ERROR_SUCCESS {
                let value = String::from_utf8_lossy(&buffer[..(bufsize as usize - 1)]);
                let value_string = value.to_string();
                println!("InstallPath: {}", value_string);
                return Some(value_string); 
            } else {
                eprintln!("RegQueryValueExA failed with error code: {:?}", query_result);
            }

            let close_result = RegCloseKey(hsubkey);
            if close_result != ERROR_SUCCESS {
                eprintln!("Failed to close registry key: {:?}", close_result);
            }
        } else {
            eprintln!("RegOpenKeyExA failed with error code: {:?}", open_result);
        }
    }
    return None;
}

読み取りの問題で、日本語は文字化けしてしまう。とはいえ、英語のみのパスを使用すればよいので一旦はこれで良し。(文字化け対処できるのであれば教えて欲しいです!)

MikutoMikuto

同様に、書き込みを行う関数を作成する。
使用するwindowsクレートの関数はRegSetKeyValueA

write
#[tauri::command]
fn get_registry_val(subkey_puth:String, value_name:String) -> Option<String> {
    let hkey: HKEY = HKEY_CURRENT_USER;  // HKEY_CURRENT_USER(0x80000001) ユーザーのルートキー
    let subkey_cstring = CString::new(subkey_puth).unwrap();    // NULL 終端が必要
    let subkey = PCSTR(subkey_cstring.as_ptr() as _);             // PCSTR に変換 指定のキーへのパス
    let valuename_cstring = CString::new(value_name).unwrap();  // NULL 終端が必要
    let valuename = PCSTR(valuename_cstring.as_ptr() as _);       // PCSTR に変換 指定の値の名前
    let mut buffer = [0u8; 256];                              // バッファ
    let mut bufsize = buffer.len() as u32;

    unsafe {
        let mut hsubkey = HKEY::default();  // サブキーのハンドル

        // サブキーを開く
        let open_result = RegOpenKeyExA(hkey, subkey, Some(0), KEY_READ, &mut hsubkey);
        if open_result == ERROR_SUCCESS {
            // サブキーが開けたら値を取得
            let query_result = RegQueryValueExA(hsubkey, valuename, None, None, Some(buffer.as_mut_ptr()), Some(&mut bufsize));
            if query_result == ERROR_SUCCESS {
                // バッファから文字列を取得
                let value = String::from_utf8_lossy(&buffer[..(bufsize as usize - 1)]);
                let value_string = value.to_string();
                println!("InstallPath: {}", value_string);
                return Some(value_string); 
            } else {
                eprintln!("RegQueryValueExA failed with error code: {:?}", query_result);
            }
            // サブキーを閉じる(重要)
            let close_result = RegCloseKey(hsubkey);
            if close_result != ERROR_SUCCESS {
                eprintln!("Failed to close registry key: {:?}", close_result);
            }
        } else {
            eprintln!("RegOpenKeyExA failed with error code: {:?}", open_result);
        }
    }
    return None;
}