0x00 说在前面的废话
2021年10月5日这一天注定是不寻常的一天......因为“巨硬”发布了Windows 11。本人在第一时间装了Windows 11。体验还算不错,下面是windows 11的开始菜单啦。感觉又要适应一段时间了。但是发现了一个问题,这货!任务栏不能改!位!置!这难不倒我吧,,上网查资料发现可以通过修改注册表来更改任务栏的位置。看到这里,要不咱们就用Rust来大干一场,正好练习下Rust的winapi。后来......就有了这篇文章。
本文也正好借此机会说下Rust使用winapi的一些坑。如果您是一直从事winapi开发的大佬,恳请大佬批评改正。本人对winapi也不是很熟悉,且Rust版的winapi也没有文档,只能通过C++的文档来写了,难免存在不足之处。
0x01 自定义windows11的任务栏位置
微软虽然没有提供修改任务栏位置的设置项,但是仍然可以通过修改注册表来达到改变任务栏的位置。操作注册表前建议备份注册表。打开注册表编辑器,定位到:\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3
,然后双击 Settings
打开。
在打开的二进制编辑器中,找到红框标注的 03(FE 下方的那个),将其修改为 00(左)、01(上)、02(右),接着使用软媒魔方重启 Windows 资源管理器,即可改变任务栏位置。
经过本人的亲测,任务栏在上下方式没有任何问题的,但是在左右两侧,会导致中间的图标显示不出来。下面是效果图。
0x02 操作注册表的常用方法
要操作Windows注册表一定需要winapi,本节课所使用的winapi库是0.3.9版本(截至写这篇文章时是最新的)。操作注册表无非就是增、删、改、查这四个方法啦。在winapi里面分别对应RegCreateKey
、RegDeleteKey
、RegSetValue
、RegQueryValue
,最后再加上一个创建方法RegOpenKey
。
简单介绍下这几个常用的相关方法吧。
RegCreateKeyExW
该方法是用来创建一个项。这个方法有9个参数,不要被吓到。有很多参数默认就可以。第一个是HKEY
类型,可以传微软默认的5个值之一。这里以HKEY_CURRENT_USER
为例。第二个参数是创建的项的名称(该字段是LPCWSTR
类型,后面会介绍如何构建这个类型),第三到第五个参数,以及第七个参数按照下方默认来写即可。第六个参数,是创建子键后的结果,是一个HKEY
类型。
let mut hkey: HKEY = null_mut();
let mut lp: Vec = OsStr::new("Software\\360\\333").encode_wide().chain(once(0)).collect();
let create_result = RegCreateKeyExW(HKEY_CURRENT_USER,
lp.as_ptr(),
0,
null_mut(),
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
null_mut(),
&mut hkey,
null_mut());
RegDeleteKeyExW
该方法是用来删除一个项。请谨慎使用该方法,一旦删除,将不可逆转。这个方法有4个参数,第一个参数同RegCreateKeyExW
方法的第一个参数。第二个参数是要删除项的名称。第三和第四按照以下代码默认即可。
let mut lp: Vec = OsStr::new("Software\\360\\333").encode_wide().chain(once(0)).collect();
let result = RegDeleteKeyExW(HKEY_CURRENT_USER, lp.as_ptr(), KEY_ALL_ACCESS, 0);
RegSetValueExW
该方法是用来修改一个键值。请谨慎使用该方法,一旦修改,将不可逆转。该方法有6个参数,第一个参数是HKEY
类型的参数,通常传递RegOpenKey
方法返回的参数。第二个参数是要修改值的键名。第三个参数默认0即可。第四个参数是你要修改值的类型,通常有REG_SZ
,REG_BINARY
,REG_DWORD
,REG_DWORD_LITTLE_ENDIAN
,REG_DWORD_BIG_ENDIAN
等10多种类型。第五个参数就是要修改的值了。第六个参数则是新值的占内存的长度了。
let mut lp: Vec = OsStr::new("Software\\360\\333").encode_wide().chain(once(0)).collect();
let mut val: Vec = OsStr::new("ABCD").encode_wide().chain(once(0)).collect();
let result = RegSetValueExW(hkey, key.as_ptr(), 0, REG_SZ, val.as_ptr() as *const u8, (size_of_val(&val) as u32));
RegQueryValueExW
该方法是用来查询一个键的当前值内容。该方法也拥有6个参数。第一个参数是HKEY
类型的参数,通常传递RegOpenKey
方法返回的参数。第二个参数是要修改值的键名称。第三个参数模式为null_mut()
,第四个参数是保存当前查询值的类型。第五个参数是保存当前值的数据内容。第六个参数是保存当前数据的长度。此方法需要调用两次。第一次是仅获取返回的数据长度,第二次调用时收集数据。因此第一次调用时,第五个参数可以为null_mut()
,第二次调用时则是一个带有长度的数组了。
let mut dword: DWORD = 0;
let mut dtype: DWORD = 0;
//查询
let status = RegQueryValueExW(*hkey,
lp.as_ptr(),
null_mut(),
&mut dtype,
null_mut(),
&mut dword);
let mut data_binary: Vec = vec![0; dword as usize];
if status == SEC_E_OK {
// 存在值
RegQueryValueExW(*hkey,
str_to_lpcwstr(key_name).as_ptr(),
null_mut(),
&mut dtype,
data_binary.as_mut_ptr(),
&mut dword);
}
RegOpenKeyW
该方法用来打开一个注册表项。这个方法很简单,该方法有三个参数。第一个参数是HKEY
类型的参数,第二个是子项的名称,第三个是打开后保存的HKEY
结果
let mut hkey: HKEY = null_mut();
let mut lp: Vec = OsStr::new("Software\\360\\333").encode_wide().chain(once(0)).collect();
let status = RegOpenKeyW(HKEY_CURRENT_USER,
lp.as_ptr(),
&mut hkey);
0x03 小结
本节课简单介绍了下使用Rust来操作注册表常用的几个参数。其实跟C++大同小异,有一点儿要注意的是Windows的16字宽的编码,下节再讲解。另外我们离windows11注册表修改的工具还比较远,希望大家耐心读文章。
0x04 关于本文源码
完整的源码,我将在该文章全部结束后放出。如果有什么不明白的可以关注公众号:《Rust学习日记》给我留言。当然源码也会通过公众号给出哟~