Windows registry with rust

i have been learning rust using the microsoft documentation of windows api and i came I across an article "How to Assign a Custom Icon to a File Type" so i wanted to implement it in rust but i have been stuck on it for the past two days here is the code sample.... I will appreciate any help thanks

extern crate winapi;
use std::{env, process};
use windows::Win32::UI::Shell::{SHChangeNotify, SHCNE_ASSOCCHANGED, SHCNF_IDLIST};
use std::ptr;
use std::ffi::{OsStr, c_void};
use std::os::windows::ffi::OsStrExt;
use winapi::um::winreg::{RegCreateKeyExW, RegSetValueExW, HKEY_CLASSES_ROOT};
use winapi::um::winnt::{KEY_WRITE, REG_SZ, REG_OPTION_NON_VOLATILE};
use winapi::shared::minwindef::{DWORD, HKEY, LPDWORD};
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::winbase::LocalFree;

fn main() {

     // Get the current executable path
     if let Some(exe_path) = current_exe_path() {
        println!("Current executable path: {}", exe_path);

        
        // For File-Type Assignment (HKEY_CLASSES_ROOT\.extension)
        set_default_icon_file_type(".chess", r".\src\chess.webp");

        // Notify the system about the icon changes
        notify_system();

        // Now you can use the executable path as needed.
        // For example, you can pass it to the functions for setting up the ProgID.
        set_default_icon_application(r".\src\chess.webp", &exe_path);
    } else {
        println!("Failed to retrieve the executable path.");
    }process::exit(1);

    
}

fn set_default_icon_file_type(extension: &str, icon_path: &str) {
    let key_path = format!(r"DefaultIcon", extension);
    set_default_icon(&HKEY_CLASSES_ROOT, key_path, icon_path);
}

fn set_default_icon_application(prog_id: &str, icon_path: &str) {
    let key_path = format!(r"DefaultIcon", prog_id);
    set_default_icon(&HKEY_CLASSES_ROOT, key_path, icon_path);
}

fn set_default_icon(root_key: &HKEY, key_path: String, icon_path: &str) {
    unsafe {
        let mut hkey: HKEY = ptr::null_mut();
        let mut disposition: DWORD = 0;

        // Create or open the registry key
        let result = RegCreateKeyExW(
            *root_key,
            key_path.as_ptr() as *const u16,
            0,
            ptr::null_mut(),
            REG_OPTION_NON_VOLATILE,
            KEY_WRITE,
            ptr::null_mut(),
            &mut hkey,
            &mut disposition,
        );

        if result == 0 {
            // Set the default value (REG_SZ) to the icon path
            let icon_path_wide: Vec<u16> = OsStr::new(icon_path).encode_wide().chain(Some(0)).collect();
            RegSetValueExW(
                hkey,
                ptr::null(),
                0,
                REG_SZ,
                icon_path_wide.as_ptr() as *const u8,
                (icon_path_wide.len() * 2) as DWORD,
            );

            // Close the registry key
            RegCloseKey(hkey);
        } else {
            println!("Failed to create or open registry key. Error code: {}", result);
        }
    }
}

// Helper function to close the registry key
fn RegCloseKey(hkey: HKEY) {
    unsafe {
        let result = winapi::um::winreg::RegCloseKey(hkey);
        if result != 0 {
            println!("Failed to close registry key. Error code: {}", result);
        }
    }
}
// Notify the system about changes
fn notify_system() {
    unsafe {
        SHChangeNotify(
            SHCNE_ASSOCCHANGED,
            SHCNF_IDLIST,
            None as Option<*const c_void>,
            None as Option<*const c_void>,
        );
    }
}

fn current_exe_path() -> Option<String> {
    if let Ok(exe_path) = std::env::current_exe() {
        if let Some(path) = exe_path.to_str() {
            Some(path.to_owned())
        } else {
            None
        }
    } else {
        None
    }
}

You haven't specified what your actual problem is. You say you are "stuck", but how? Does it not compile? What's the error message? Does it crash when you run it? Where, and in what way? Does it run but just not work?

Three things I spotted at the top: extern crate items haven't been needed in years; wherever you learned that from is probably very out of date. Second, I would not mix winapi and windows: they both do the same thing, but won't necessarily be compatible with each other. Three: as far as I know, you can't use a WebP (or any arbitrary image format) as an icon in Windows. Icons need to be, y'know, icon files. Or an icon file stored as a resource in an executable.

2 Likes

thank you yes the code does run with zero errors and can u emphasize on your last statement concerning "Icons need to be icon files" thanks once again Daniel

In fact, the DefaultIcon default value needs to be the full path to a DLL or executable, followed by a comma, then the index of the icon in the file’s resource section; and that icon needs to be in the format expected by Windows APIs.

A second issue is that DefaultIcon should not be located under HKCR\.chess, but that the default value of HKCR\.chess should be a short file type, like chessfile, and then the default value of HKCR\chessfile\DefaultIcon should be the executable path and icon index. I recommend verifying what you’re trying to do using regedit before writing Rust code to do the same thing.

You also have an issue in the line key_path.as_ptr() as *const u16, which passes a UTF-8 string to a LPCWSTR 16-bit string parameter. This needs to be encoded in the same way as icon_path_wide a bit further down.

1 Like