初始提交

This commit is contained in:
2026-08-26 18:48:17 +08:00
commit 3c6ff7d205
5 changed files with 386 additions and 0 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 editgpu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

97
README.md Normal file
View File

@@ -0,0 +1,97 @@
# ⚠️ 重要声明 ⚠️
> # 🚨 免责声明
>
> ## 本工具仅供学习交流使用!
>
> ### 请勿用于任何商业用途、违法用途或对他人造成损害的用途!
>
> **使用本工具所造成的一切后果,由使用者自行承担!**
>
> - 修改注册表可能导致系统不稳定、驱动异常、设备无法识别等问题
> - 请在操作前自行备份注册表与重要数据
> - 操作需谨慎,风险自负
---
# 显卡名称修改工具 (GPU Rename)
一个用于修改 Windows 系统显卡显示名称的 Go 命令行小工具。
## ✨ 功能特性
- 自动枚举当前**实际连接**的物理显卡(PCI 总线),过滤掉幽灵设备与虚拟显示适配器
- 显卡数量 > 1 时,列出列表供用户选择
- 支持自定义显卡显示名称
- 修改完成后自动验证结果
- 修改成功后提示重启机器
## 🖥️ 运行环境
- Windows 7 / 8 / 10 / 11
- 需要 **管理员权限** 运行(修改注册表 HKLM 需要)
## 📦 编译
```bash
# 使用 Go 1.21+ 编译
go mod tidy
go build -o editgpu.exe .
```
或直接使用已编译好的 `editgpu.exe`。
## 🚀 使用方法
1. **右键** 以管理员身份运行 `editgpu.exe`
2. 程序自动检测物理显卡:
- 只有 1 块显卡:直接选中
- 多块显卡:输入序号选择要修改的显卡
3. 输入新的显卡名称(直接回车可取消)
4. 程序自动修改注册表并验证
5. 看到「修改成功」提示后,**重启电脑**使修改完全生效
## ⚙️ 工作原理
程序通过 Windows SetupAPI 枚举当前存在的显卡设备:
1. 使用 `DIGCF_PRESENT` 标志只获取当前实际连接的设备,排除历史遗留的幽灵设备
2. 通过 `SPDRP_ENUMERATOR_NAME == "PCI"` 过滤,只保留物理显卡,排除虚拟显示适配器
3. 获取设备实例 ID,映射到注册表路径 `HKLM\SYSTEM\CurrentControlSet\Enum\...`
4. 修改该路径下的 `DeviceDesc` 注册表值
## 📁 文件结构
```
editgpu/
├── main.go # 主程序源码
├── go.mod # Go 模块配置
├── go.sum # 依赖校验文件
└── README.md # 本说明文档
```
## ❓ 常见问题
**Q:提示「请以管理员身份运行」?**
A:修改注册表需要管理员权限,请右键选择「以管理员身份运行」。
**Q:修改后设备管理器不显示新名称?**
A:请重启电脑,重启后设备管理器会刷新显示新名称。
**Q:修改名称会影响显卡性能吗?**
A:不会,仅修改显示名称,不影响硬件本身与驱动功能。
**Q:如何恢复原始名称?**
A:重新运行本工具,输入原始显卡名称再次修改即可;或到设备管理器卸载设备后重新扫描硬件。
---
# ⚠️ 再次提醒 ⚠️
> ## 本工具仅供学习交流使用
>
> ### 因使用本工具产生的一切后果,由使用者自行承担!
>
> #### 请勿将本工具用于非法用途、商业用途或损害他人利益!

5
go.mod Normal file
View File

@@ -0,0 +1,5 @@
module editgpu
go 1.25.0
require golang.org/x/sys v0.47.0

2
go.sum Normal file
View File

@@ -0,0 +1,2 @@
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=

261
main.go Normal file
View File

@@ -0,0 +1,261 @@
package main
import (
"bufio"
"fmt"
"os"
"strings"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
)
// 显卡类 GUID
var gpuClassGUID = windows.GUID{
Data1: 0x4d36e968,
Data2: 0xe325,
Data3: 0x11ce,
Data4: [8]byte{0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18},
}
// GPUInfo 保存一张显卡的信息
type GPUInfo struct {
Name string // 显示名称
Path string // 注册表枚举路径(HKLM\SYSTEM\CurrentControlSet\Enum\...)
ID string // 设备实例 ID
}
func main() {
fmt.Println("============================================")
fmt.Println(" 显卡名称修改工具 (GPU Rename) ")
fmt.Println("============================================")
fmt.Println()
// 1. 枚举当前实际存在的物理显卡
gpus, err := enumerateGPUs()
if err != nil {
fmt.Printf("错误:枚举显卡失败 - %v\n", err)
fmt.Println("提示:请以管理员身份运行本程序。")
waitEnter()
return
}
if len(gpus) == 0 {
fmt.Println("错误:未检测到任何物理显卡设备。")
waitEnter()
return
}
// 2. 选择目标显卡
var target GPUInfo
if len(gpus) > 1 {
fmt.Printf("检测到 %d 块物理显卡,请选择要修改的显卡:\n", len(gpus))
for i, g := range gpus {
fmt.Printf(" [%d] %s\n", i+1, g.Name)
}
fmt.Println()
target, err = chooseGPU(gpus)
if err != nil {
fmt.Printf("错误:%v\n", err)
waitEnter()
return
}
} else {
target = gpus[0]
fmt.Printf("检测到 1 块物理显卡:%s\n\n", target.Name)
}
fmt.Printf("当前选中显卡:%s\n", target.Name)
fmt.Printf("设备实例 ID:%s\n\n", target.ID)
// 3. 输入新名称
newName := readNewName()
if newName == "" {
fmt.Println("已取消操作。")
waitEnter()
return
}
fmt.Printf("即将把显卡名称修改为:%s\n", newName)
// 4. 执行修改
if err := renameGPU(target, newName); err != nil {
fmt.Printf("错误:修改失败 - %v\n", err)
fmt.Println("请确认已使用管理员权限运行。")
waitEnter()
return
}
fmt.Println("修改已写入注册表,正在验证...")
// 5. 验证修改结果
verifyName, err := verifyGPU(target)
if err != nil {
fmt.Printf("警告:验证时发生错误 - %v\n", err)
} else if verifyName == newName {
fmt.Println("验证通过:显卡名称已成功修改为指定值。")
} else {
fmt.Printf("警告:验证结果与预期不一致,当前值为:%s\n", verifyName)
fmt.Println(" 部分设备可能需要重启后才会在设备管理器中刷新。")
}
fmt.Println()
fmt.Println("============================================")
fmt.Println(" 修改成功!请重启机器以使修改完全生效。 ")
fmt.Println("============================================")
waitEnter()
}
// enumerateGPUs 使用 SetupAPI 枚举当前实际存在的物理显卡。
// 使用 DIGCF_PRESENT 标志,只列出真正连接在机器上的设备,
// 并过滤掉虚拟显示适配器(无物理设备对象名)。
func enumerateGPUs() ([]GPUInfo, error) {
// 只枚举当前存在的设备(DIGCF_PRESENT)
devSet, err := windows.SetupDiGetClassDevsEx(
&gpuClassGUID,
"",
0,
windows.DIGCF_PRESENT,
0,
"",
)
if err != nil {
return nil, err
}
defer windows.SetupDiDestroyDeviceInfoList(devSet)
var gpus []GPUInfo
for i := 0; ; i++ {
devInfo, err := windows.SetupDiEnumDeviceInfo(devSet, i)
if err != nil {
break // 枚举完毕
}
// 过滤:只保留物理显卡(PCI 总线上的设备),
// 排除 ROOT\SWD 等虚拟显示适配器。
enumerator := ""
if v, err := windows.SetupDiGetDeviceRegistryProperty(devSet, devInfo, windows.SPDRP_ENUMERATOR_NAME); err == nil {
if s, ok := v.(string); ok {
enumerator = s
}
}
if !strings.EqualFold(enumerator, "PCI") {
continue
}
// 获取实例 ID
instanceID, err := windows.SetupDiGetDeviceInstanceId(devSet, devInfo)
if err != nil {
continue
}
// 获取显示名称(优先 FriendlyName,其次 DeviceDesc)
name := getDeviceName(devSet, devInfo, instanceID)
gpus = append(gpus, GPUInfo{
Name: name,
Path: instanceIDToRegPath(instanceID),
ID: instanceID,
})
}
return gpus, nil
}
// getDeviceName 获取设备显示名称,优先 FriendlyName,回退到 DeviceDesc
func getDeviceName(devSet windows.DevInfo, devInfo *windows.DevInfoData, fallback string) string {
if v, err := windows.SetupDiGetDeviceRegistryProperty(devSet, devInfo, windows.SPDRP_FRIENDLYNAME); err == nil {
if s, ok := v.(string); ok && strings.TrimSpace(s) != "" {
return s
}
}
if v, err := windows.SetupDiGetDeviceRegistryProperty(devSet, devInfo, windows.SPDRP_DEVICEDESC); err == nil {
if s, ok := v.(string); ok && strings.TrimSpace(s) != "" {
return cleanDeviceDesc(s)
}
}
return fallback
}
// instanceIDToRegPath 将设备实例 ID 转换为注册表枚举路径。
// 例如 PCI\VEN_10DE&DEV_1DB1...\4&31024D2F&0&0018
// -> SYSTEM\CurrentControlSet\Enum\PCI\VEN_10DE&DEV_1DB1...\4&31024D2F&0&0018
func instanceIDToRegPath(instanceID string) string {
return `SYSTEM\CurrentControlSet\Enum\` + instanceID
}
// cleanDeviceDesc 去掉 DeviceDesc 中的 INF 引用前缀,只保留可读名称
func cleanDeviceDesc(desc string) string {
if idx := strings.LastIndex(desc, ";"); idx >= 0 && idx < len(desc)-1 {
return desc[idx+1:]
}
return desc
}
// getDeviceDesc 读取注册表中的 DeviceDesc
func getDeviceDesc(regPath string) (string, error) {
k, err := registry.OpenKey(registry.LOCAL_MACHINE, regPath, registry.QUERY_VALUE)
if err != nil {
return "", err
}
defer k.Close()
v, _, err := k.GetStringValue("DeviceDesc")
return v, err
}
// chooseGPU 让用户从列表中选择一块显卡
func chooseGPU(gpus []GPUInfo) (GPUInfo, error) {
reader := bufio.NewReader(os.Stdin)
for {
fmt.Printf("请输入显卡序号 (1-%d):", len(gpus))
input, _ := reader.ReadString('\n')
input = strings.TrimSpace(input)
var idx int
if _, err := fmt.Sscanf(input, "%d", &idx); err != nil {
fmt.Println("输入无效,请输入数字。")
continue
}
if idx < 1 || idx > len(gpus) {
fmt.Printf("序号超出范围,请输入 1-%d。\n", len(gpus))
continue
}
return gpus[idx-1], nil
}
}
// readNewName 读取用户输入的新名称
func readNewName() string {
reader := bufio.NewReader(os.Stdin)
fmt.Print("请输入新的显卡名称(直接回车取消):")
input, _ := reader.ReadString('\n')
return strings.TrimSpace(input)
}
// renameGPU 修改注册表中的 DeviceDesc
func renameGPU(g GPUInfo, newName string) error {
k, err := registry.OpenKey(registry.LOCAL_MACHINE, g.Path, registry.SET_VALUE)
if err != nil {
return err
}
defer k.Close()
return k.SetStringValue("DeviceDesc", newName)
}
// verifyGPU 重新读取 DeviceDesc 进行验证
func verifyGPU(g GPUInfo) (string, error) {
desc, err := getDeviceDesc(g.Path)
if err != nil {
return "", err
}
return cleanDeviceDesc(desc), nil
}
// waitEnter 等待用户按键后退出
func waitEnter() {
fmt.Println()
fmt.Print("按回车键退出...")
bufio.NewReader(os.Stdin).ReadString('\n')
}