2024-08-26 更改驱动器号导致的软件崩溃问题

​ 在给电脑重新分盘时,想把 Software 盘的驱动器号(E:)改为对应的首字母 S,因此导致了所有软件崩溃。主要原因是软件主要依据驱动器号识别位置,而更改驱动器号后,并不会将软件设置的驱动器号一并更改。

​ 解决办法有如下两个:

  1. 删除原有软件文件夹,重装一遍。
  2. 手动更改注册表,将 E:\ 改为 S:\。

​ 两个方案的工作量都不小:

  • 方案一的缺点是,注册表中原有的记录不会被删除,在操作电脑时会偶尔弹出一些无图标的选项很烦人。
  • 方案二的缺点是,难以更改完全,因为不清楚每个软件安装和使用时都向注册表写了些什么东西。。。

​ 这里介绍一下方案二的解决办法,但也并不是很好的方案。

1 手动替换

​ win11下,点击 win 按键,搜索框里搜索“注册表”,打开“注册表编辑器”后,点击左上角“编辑 -> 查找”选项,搜索更改前的盘符,点击“查找下一个。此处我输入 “E:\”。

image-20240826005740290

​ 可以看到,搜索到了一个结果,即软件安装时写入的注册表数据。双击“URL Protocol”,将其手动替换为“S:\BcutBilibili\Bcut.exe”。

2 Python 替换

​ 手动替换效率过慢,因此使用 Python 来自动替换。给出如下示例代码。

​ 注意:在运行代码时,需要右键点击 Python 或 IDE 图标(如 PyCharm、VS Code),并选择“以管理员身份运行”。否则,会抛出错误:[WinError 5] 拒绝访问

import re
import winreg as reg


def replace_all(old_drive_pattern, new_drive, access_flag=0):
    # 打开注册表根键
    replace_root(reg.HKEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT", "", old_drive_pattern, new_drive, access_flag)
    replace_root(reg.HKEY_CURRENT_USER, "HKEY_CURRENT_USER", "", old_drive_pattern, new_drive, access_flag)
    replace_root(reg.HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE", "", old_drive_pattern, new_drive, access_flag)
    replace_root(reg.HKEY_USERS, "HKEY_USERS", "", old_drive_pattern, new_drive, access_flag)
    replace_root(reg.HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG", "", old_drive_pattern, new_drive, access_flag)


def replace_root(root_key, root_name, key_path, old_drive_pattern, new_drive, access_flag=0):
    try:
        # 打开注册表键
        reg_key = reg.OpenKey(root_key, key_path, 0, reg.KEY_READ | reg.KEY_WRITE | access_flag)

        # 遍历所有值
        i = 0
        while True:
            try:
                value_name, value_data, value_type = reg.EnumValue(reg_key, i)

                # 处理 REG_SZ 和 REG_EXPAND_SZ 类型的值
                if value_type == reg.REG_SZ or value_type == reg.REG_EXPAND_SZ:
                    if re.search(old_drive_pattern, value_data):
                        new_value_data = re.sub(old_drive_pattern, new_drive, value_data)
                        reg.SetValueEx(reg_key, value_name, 0, value_type, new_value_data)
                        print(f"{root_name}\\{key_path}\\{value_name}:\n{value_data}\n修改为 -> {new_value_data}\n")

                # 处理 REG_MULTI_SZ 类型的值
                elif value_type == reg.REG_MULTI_SZ:
                    new_value_data = []
                    modified = False
                    for item in value_data:
                        if re.search(old_drive_pattern, item):
                            new_value_data.append(re.sub(old_drive_pattern, new_drive, item))
                            modified = True
                        else:
                            new_value_data.append(item)

                    if modified:
                        reg.SetValueEx(reg_key, value_name, 0, value_type, new_value_data)
                        print(f"{root_name}\\{key_path}\\{value_name}:\n{value_data}\n修改为 -> {new_value_data}\n")

                # 替换键名
                if re.search(old_drive_pattern, value_name):
                    reg.DeleteValue(reg_key, value_name)  # 删除旧的键值对
                    new_name = re.sub(old_drive_pattern, new_drive, value_name)
                    reg.SetValueEx(reg_key, new_name, 0, value_type, value_data)  # 创建新的键值对,保留值不变,仅更改键名
                    print(f"{root_name}\\{key_path}:\n修改了键名: {value_name}\n修改为 -> {new_name}\n")

                i += 1
            except OSError:
                break

        # 遍历子键
        i = 0
        while True:
            try:
                subkey_name = reg.EnumKey(reg_key, i)
                subkey_path = f"{key_path}\\{subkey_name}"
                if key_path == "":  # 根目录不添加反斜杠 \
                    subkey_path = subkey_name
                replace_root(root_key, root_name, subkey_path, old_drive_pattern, new_drive, access_flag)
                i += 1
            except OSError:
                break

        reg.CloseKey(reg_key)
    except PermissionError:
        # print(f"没有权限访问键: {key_path}")
        pass
    except FileNotFoundError:
        # print(f"未找到键: {key_path}")
        pass
    except Exception as e:
        # print(f"无法打开键: {key_path}, 错误: {e}")
        pass


# 正则表达式模式,仅匹配以"E:\"开头的路径,确保盘符后面直接跟随的是反斜杠
old_drive_pattern = r"(?<![A-Z])E:\\"

# 设置新盘符
new_drive = r"S:\\"

# 访问 64 位注册表视图
access_flag = reg.KEY_WOW64_64KEY

# replace_root(reg.HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE", "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\Folders", old_drive_pattern, new_drive, access_flag)
replace_all(old_drive_pattern, new_drive, access_flag)

print("所有修改完成。")

2.1 注册表数据说明

​ 需要修改的注册表的数据分为以下几种:

  1. REG_SZ:字符串类型(单行)。
  1. REG_EXPAND_SZ:可延展字符串,即字符串中含有其他变量的值,类似 C# 内插字符串。
image-20240826012350274
  1. REG_MULTI_SZ:字符串类型(多行)。
image-20240826012434887

​ 在 replace_root() 函数中,对每种类型进行了分类处理。主要过程还是字符串的匹配替换,以及注册表的读取和写入。

  • REG_SZ 和 REG_EXPAND_SZ:

    在程序中,对应的 value_data 为字符串,直接匹配替换即可。

  • REG_MULTI_SZ:

    在程序中,对应的 value_data 为字符串列表,需要遍历其中的字符串进行匹配替换。

  • 键名:

    在程序中,value_name 也是字符串,直接匹配替换即可。

2.2 正则匹配

​ 使用正则匹配:old_drive_pattern = r"(?<![A-Z])E:\\"(?<![A-Z]) 是一个负向前瞻断言,确保在 E: 之前没有大写字母。防止像 "SOME:\XXX" 类似情况被匹配。

2.3 其他

  1. 推荐最好先进行测试,并备份注册表,以防出错。测试时可将 92 行取消注释,并注释 93 行。在 92 行指定测试的路径,这样即便出错,也仅是小范围,方便更改回来。
  2. 测试通过时,建议程序多运行几次,以更改完全。
  3. 可以根据具体需求更改正则匹配。
  4. 注册表部分内容在程序运行时不允许更改,需重启电脑后才能生效。
  5. 完成注册表修改后,先测试相关软件或功能是否按预期运行。如果没有生效,再考虑重启。如果不确定某些系统配置的更改是否需要重启,重启电脑可以确保所有更改生效。

3 图标问题

​ 对于桌面上已经失效的图标,只有一个个手动更改路径了。

​ 或者将其删除,然后新创建桌面快捷方式,但也需要一个个创建。

4 总结

​ 最好是不要替换盘符,新电脑分区时一旦确定后就不要更改,因为永远不清楚安装的什么软件在什么时候向注册表写了哪些东西。

​ 花了快 2 天时间,初步解决问题。但不清楚后续可能发生什么其他问题,遇到了再说吧!

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蔗理苦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值