移除 Releases 和 Test 目录(按规范只同步 Code 内容)

This commit is contained in:
2026-03-20 06:57:29 +08:00
parent 45e7d9553a
commit 2747b69b56
14 changed files with 0 additions and 2430 deletions

View File

@@ -1,181 +0,0 @@
# 远程音量监控工具 V1.0
Windows 远程连接音量自动调节器 - 检测到 RDP 远程连接时自动调整系统音量
---
## 🚀 快速开始
### 1. 安装依赖工具(推荐)
下载 nircmd.exe 放到 `tools` 文件夹:
- 64 位https://www.nirsoft.net/utils/nircmd-x64.zip
- 32 位https://www.nirsoft.net/utils/nircmd.zip
解压后将 `nircmd.exe` 复制到 `tools\` 目录
### 2. 运行程序
**方式 1使用启动脚本**
```bat
scripts\启动监控.bat
```
**方式 2直接运行**
```bat
python src\remote_volume_monitor.py
```
**方式 3测试模式**
```bat
python src\remote_volume_monitor.py --test
```
---
## 📋 功能特性
- ✅ 自动检测 RDP 远程连接/断开
- ✅ 连接时自动降低音量(默认 30%
- ✅ 断开时自动恢复音量(默认 80%
- ✅ 零第三方 Python 依赖
- ✅ 支持 nircmd/Core Audio/PowerShell 多种方案
- ✅ 配置文件可自定义
- ✅ 后台服务模式
---
## ⚙️ 配置说明
编辑 `config\config.ini`
```ini
[volume]
# 远程连接时的音量 (0-100)
remote_volume = 30
# 本地使用时的音量 (0-100)
local_volume = 80
[monitor]
# 检测间隔(秒)
check_interval = 5
[behavior]
# 连接时调整音量
adjust_on_connect = true
# 断开时恢复音量
adjust_on_disconnect = true
```
---
## 📁 文件结构
```
remote-volume-monitor-v1.0/
├── src/
│ └── remote_volume_monitor.py # 主程序
├── config/
│ └── config.ini # 配置文件
├── tools/
│ ├── README.md # 工具说明
│ └── nircmd.exe # 音量工具(需自行放入)
├── scripts/
│ └── 启动监控.bat # 启动脚本
├── docs/
│ ├── 部署检查清单_远程音量控制.md
│ └── 音量控制方案说明.md
├── logs/ # 日志目录(运行时自动创建)
├── README.md # 本文件
└── requirements.txt # 依赖说明
```
---
## 🧪 常用命令
```bash
# 测试模式(检测一次后退出)
python src\remote_volume_monitor.py --test
# 获取当前音量
python src\remote_volume_monitor.py --get-volume
# 设置音量
python src\remote_volume_monitor.py --set-volume 50
# 创建配置文件
python src\remote_volume_monitor.py --create-config
# 启动监控
python src\remote_volume_monitor.py
# 使用启动脚本
scripts\启动监控.bat
```
---
## 📊 系统要求
- **操作系统:** Windows 10/11
- **Python** 3.8 或更高版本
- **权限:** 普通用户权限即可(安装服务需要管理员)
- **音频设备:** 必须有活跃的音频输出设备
---
## 🐛 故障排查
### 问题 1无法检测 RDP 连接
**检查:**
```bash
python src\test_rdp_detection.py
```
### 问题 2音量无法调节
**解决:**
1. 确认已下载 nircmd.exe 放到 `tools` 文件夹
2. 检查 Windows Audio 服务是否运行
3. 查看日志文件 `logs\remote_volume.log`
### 问题 3断开 RDP 后音量不恢复
**检查:**
```bash
python src\test_rdp_disconnect.py
```
---
## 📖 详细文档
- **部署指南:** `docs\部署检查清单_远程音量控制.md`
- **音量方案:** `docs\音量控制方案说明.md`
- **工具说明:** `tools\README.md`
---
## 📝 版本信息
- **版本号:** V1.0
- **发布日期:** 2026-03-07
- **依赖:** 零第三方 Python 依赖
- **推荐工具:** nircmd.exe35KB 免费工具)
---
## 📞 技术支持
查看日志文件获取详细信息:
```
logs\remote_volume.log
```
---
*远程音量监控工具 V1.0 - 零依赖版本*

View File

@@ -1,28 +0,0 @@
# 远程连接音量自动调节器 - 配置文件
# Remote Volume Monitor Configuration
[volume]
# 远程连接时的音量 (0-100)
remote_volume = 30
# 本地使用时的音量 (0-100, 可选)
# 如果设置,断开远程连接时会自动恢复
local_volume = 80
[monitor]
# 检测间隔 (秒)
check_interval = 5
[behavior]
# 检测到远程连接时是否调整音量
adjust_on_connect = true
# 检测到远程连接断开时是否恢复音量
adjust_on_disconnect = true
[logging]
# 日志级别DEBUG, INFO, WARNING, ERROR
level = INFO
# 日志文件路径
log_file = remote_volume.log

View File

@@ -1,254 +0,0 @@
# 远程音量控制 - 部署检查清单
## 📦 部署前准备
### 1. 环境检查
- [ ] 目标电脑已安装 Windows 10/11
- [ ] 已安装 Python 3.8 或更高版本
- [ ] 确认 Python 已添加到系统 PATH
- [ ] 确认有管理员权限(用于安装服务)
- [ ] 确认 Windows Audio 服务正在运行
### 2. 文件准备
- [ ] remote_volume_monitor.py主程序
- [ ] config.ini配置文件
- [ ] 启动监控.bat启动脚本
- [ ] requirements.txt依赖列表
- [ ] README_远程音量控制.md使用文档
- [ ] 测试用例_远程音量控制.md测试文档
- [ ] 部署检查清单.md本文档
### 3. 依赖安装
```bash
# 方法 1: 使用 requirements.txt
pip install -r requirements.txt
# 方法 2: 手动安装
pip install pycaw comtypes wmi pywin32
```
- [ ] pycaw 安装成功
- [ ] comtypes 安装成功
- [ ] wmi 安装成功
- [ ] pywin32 安装成功
---
## 🚀 部署步骤
### 步骤 1: 文件部署
将以下文件复制到目标电脑(建议路径:`C:\Program Files\RemoteVolumeMonitor\`
- [ ] 复制所有项目文件到目标目录
- [ ] 确认文件权限正确
- [ ] 创建日志目录(可选)
### 步骤 2: 配置调整
编辑 `config.ini`
```ini
[volume]
remote_volume = 30 # 根据实际需求调整
local_volume = 80 # 可选,断开时恢复
[monitor]
check_interval = 5 # 检测间隔(秒)
[behavior]
adjust_on_connect = true
adjust_on_disconnect = true
```
- [ ] 设置目标音量
- [ ] 设置检测间隔
- [ ] 配置行为选项
### 步骤 3: 功能测试
运行测试模式:
```bash
python remote_volume_monitor.py --test
```
- [ ] 程序无报错
- [ ] 能正确检测当前会话状态
- [ ] 音量控制器初始化成功
### 步骤 4: 手动启动测试
```bash
python remote_volume_monitor.py --config config.ini
```
- [ ] 程序正常启动
- [ ] 日志文件开始记录
- [ ] 无异常错误
### 步骤 5: RDP 连接测试
1. 使用另一台电脑 RDP 连接到目标电脑
2. 观察音量变化
3. 查看日志记录
4. 断开 RDP 连接
5. 观察音量恢复(如果配置了)
- [ ] 连接时音量自动降低
- [ ] 断开时音量自动恢复
- [ ] 日志记录完整
- [ ] 响应时间 < 5 秒
### 步骤 6: 安装为服务(可选,推荐)
**下载 NSSM**: https://nssm.cc/download
**以管理员身份运行 CMD**:
```bash
cd C:\Program Files\RemoteVolumeMonitor
nssm install RemoteVolumeMonitor "C:\Python39\python.exe" "C:\Program Files\RemoteVolumeMonitor\remote_volume_monitor.py" "--config" "C:\Program Files\RemoteVolumeMonitor\config.ini"
nssm set RemoteVolumeMonitor DisplayName "Remote Volume Monitor"
nssm set RemoteVolumeMonitor Description "自动检测远程连接并调整系统音量"
nssm set RemoteVolumeMonitor Start SERVICE_AUTO_START
nssm set RemoteVolumeMonitor ObjectName LocalSystem
nssm start RemoteVolumeMonitor
```
- [ ] NSSM 已下载
- [ ] 服务安装成功
- [ ] 服务启动成功
- [ ] 设置开机自启
- [ ] 重启电脑验证服务自动启动
---
## ✅ 验收检查
### 功能验收
- [ ] 能准确检测 RDP 连接建立
- [ ] 能准确检测 RDP 连接断开
- [ ] 连接时音量自动调整到设定值
- [ ] 断开时音量自动恢复(如果配置)
- [ ] 配置修改后生效
- [ ] 日志记录完整准确
### 性能验收
- [ ] CPU 占用 < 1%
- [ ] 内存占用 < 50MB
- [ ] 检测延迟 < 5 秒
- [ ] 能稳定运行 24 小时
- [ ] 无内存泄漏
### 稳定性验收
- [ ] 多次连接/断开无异常
- [ ] 网络波动不影响程序
- [ ] 系统重启后自动恢复(服务模式)
- [ ] 无崩溃现象
---
## 📝 部署记录
| 项目 | 内容 |
|------|------|
| 部署日期 | _______________ |
| 部署人员 | _______________ |
| 目标电脑 | _______________ |
| 电脑名称 | _______________ |
| IP 地址 | _______________ |
| 部署方式 | ⬜ 手动启动 ⬜ Windows 服务 |
| 配置音量 | 远程____% 本地____% |
| 检测间隔 | ____ 秒 |
---
## 🐛 问题记录
### 问题 1
**描述**: _______________
**解决方案**: _______________
**状态**: ⬜ 已解决 ⬜ 待解决
### 问题 2
**描述**: _______________
**解决方案**: _______________
**状态**: ⬜ 已解决 ⬜ 待解决
---
## ✅ 部署完成确认
- [ ] 所有部署步骤已完成
- [ ] 功能测试全部通过
- [ ] 性能指标达标
- [ ] 用户已培训
- [ ] 文档已交付
- [ ] 问题已记录
**部署负责人**: _______________
**验收人**: _______________
**日期**: _______________
---
## 📞 运维支持
### 常见问题
**Q1: 程序无法启动**
- 检查 Python 是否安装
- 检查依赖是否完整
- 查看日志文件错误信息
**Q2: 音量无法调节**
- 检查音频设备是否正常
- 以管理员身份运行
- 检查 Windows Audio 服务
**Q3: 无法检测远程连接**
- 检查 WMI 服务是否运行
- 检查防火墙设置
- 查看日志诊断信息
**Q4: 服务无法启动**
- 确认以管理员权限安装
- 检查 NSSM 配置
- 查看 Windows 事件查看器
### 日志位置
默认日志文件:`remote_volume.log`(程序运行目录)
### 服务管理
```bash
# 查看服务状态
nssm status RemoteVolumeMonitor
# 停止服务
nssm stop RemoteVolumeMonitor
# 启动服务
nssm start RemoteVolumeMonitor
# 删除服务
nssm remove RemoteVolumeMonitor
```
---
**部署完成后,请将此文档上传到飞书任务管理表!**

View File

@@ -1,222 +0,0 @@
# 音量控制方案说明
## ⚠️ 关于错误码 -2147221164 (0x80040154)
如果你看到以下错误:
```
✗ 创建设备枚举器失败,错误码:-2147221164 (0x80040154)
```
这表示 **Core Audio API 初始化失败**。原因可能是:
- Windows N 版本(欧洲版,缺少媒体功能包)
- 系统音频服务异常
- COM 组件注册问题
- 权限问题
---
## ✅ 解决方案
程序已自动降级到备用方案,**仍可正常工作**
### 方案对比
| 方案 | 精度 | 可靠性 | 依赖 | 推荐度 |
|------|------|--------|------|--------|
| **nircmd** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 需下载 35KB 工具 | ⭐⭐⭐⭐⭐ 强烈推荐 |
| Core Audio API | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 无 | ⭐⭐⭐ |
| PowerShell | ⭐⭐⭐ | ⭐⭐⭐⭐ | 无 | ⭐⭐⭐ |
| SendMessage | ⭐⭐ | ⭐⭐⭐⭐ | 无 | ⭐⭐ |
---
## 🎯 推荐方案:安装 nircmd最佳体验
### 步骤 1下载 nircmd
访问https://www.nirsoft.net/utils/nircmd.html
或直接下载:
- 32 位https://www.nirsoft.net/utils/nircmd.zip
- 64 位https://www.nirsoft.net/utils/nircmd-x64.zip
### 步骤 2安装
**方法 A放到系统 PATH推荐**
```
1. 解压 nircmd.zip
2. 复制 nircmd.exe 到 C:\Windows\
3. 完成!
```
**方法 B放到程序目录**
```
1. 解压 nircmd.zip
2. 复制 nircmd.exe 到 remote-volume-monitor\ 目录
3. 完成!
```
### 步骤 3验证
```bash
nircmd setsysvolume 32767
```
如果音量变为 50%,说明安装成功!
---
## 🔧 各方案详细说明
### 方案 1nircmd推荐
**优点:**
- ✅ 最可靠100% 成功
- ✅ 精确控制音量0-100%
- ✅ 支持获取当前音量
- ✅ 仅 35KB无需安装
- ✅ 免费软件
**缺点:**
- ⚠️ 需要手动下载(一次下载,永久使用)
**使用命令:**
```bash
# 设置音量为 50%
nircmd setsysvolume 32767
# 设置音量为 30%
nircmd setsysvolume 19660
# 获取音量(返回值 0-65535
nircmd cmdoutputget sysvolume
```
---
### 方案 2Core Audio APIctypes
**优点:**
- ✅ 无需额外工具
- ✅ 精确控制音量
**缺点:**
- ❌ 可能失败(如你遇到的错误)
- ❌ 代码复杂,维护成本高
**适用场景:**
- 标准 Windows 10/11 专业版/家庭版
- 非 N 版本系统
---
### 方案 3PowerShell
**优点:**
- ✅ Windows 自带
- ✅ 无需额外工具
**缺点:**
- ⚠️ 精度有限
- ⚠️ 无法精确获取音量
**使用示例:**
```powershell
# 模拟音量键(不精确)
Add-Type -AssemblyName System.Windows.Forms
```
---
### 方案 4SendMessage
**优点:**
- ✅ 100% 可用
- ✅ 无需任何依赖
**缺点:**
- ❌ 只能模拟按键,无法设置精确音量
- ❌ 无法获取当前音量
---
## 📋 程序自动选择逻辑
```
1. 检查 nircmd.exe 是否在 PATH 或程序目录
└─ 是 → 使用 nircmd最佳
└─ 否 → 继续
2. 尝试初始化 Core Audio API
└─ 成功 → 使用 Core Audio
└─ 失败 → 继续
3. 检查 PowerShell 是否可用
└─ 是 → 使用 PowerShell
└─ 否 → 继续
4. 使用 SendMessage 模拟按键(最后备用)
```
---
## 🧪 测试你的配置
```bash
cd remote-volume-monitor
# 测试模式
python src\remote_volume_monitor.py --test
# 预期输出:
# ✓ 音量控制器nircmd (或 PowerShell/SendMessage)
# ✓ RDP 监控器初始化成功
# 音量控制器:✓ 就绪
```
---
## 💡 常见问题
### Q1: 我不想下载 nircmd能用吗
**A:** 可以!程序会自动使用 PowerShell 或 SendMessage 方案,但精度会受限。
### Q2: 为什么 Core Audio 会失败?
**A:** 可能原因:
- Windows N 版本(需要安装媒体功能包)
- Windows Audio 服务未运行
- 系统权限问题
### Q3: 如何检查我的 Windows 版本?
**A:**
```bash
# 查看 Windows 版本
winver
# 查看是否为 N 版本
systeminfo | findstr /B /C:"OS Name"
```
如果显示 "Windows 10/11 Pro N" 或 "Home N",就是 N 版本。
### Q4: N 版本如何修复?
**A:** 安装媒体功能包:
https://support.microsoft.com/zh-cn/topic/媒体功能包-for-windows-10-version-2004-85c94d1c-6077-4f41-8093-55c92a318272
或者直接下载 nircmd更简单
---
## 📞 总结
| 你的情况 | 建议 |
|---------|------|
| 看到 0x80040154 错误 | 下载 nircmd5 分钟搞定) |
| 不想下载额外工具 | 使用 PowerShell 方案(精度有限) |
| 需要精确控制 | 必须用 nircmd 或修复 Core Audio |
| 企业环境无法下载 | 联系 IT 安装媒体功能包 |
---
**推荐操作:** 下载 nircmd放到 `C:\Windows\` 目录,问题解决!
下载地址https://www.nirsoft.net/utils/nircmd.html

View File

@@ -1,38 +0,0 @@
# 远程音量监控工具 V1.0 - 依赖说明
## Python 依赖
**零第三方依赖!** 仅使用 Python 标准库:
- ctypes
- os
- subprocess
- configparser
- logging
- time
- pathlib
## 系统要求
- Windows 10/11
- Python 3.8+
## 推荐工具(可选)
### nircmd.exe强烈推荐
用途:精确控制 Windows 系统音量
下载:
- 64 位https://www.nirsoft.net/utils/nircmd-x64.zip
- 32 位https://www.nirsoft.net/utils/nircmd.zip
安装:
1. 解压 ZIP 文件
2. 将 nircmd.exe 复制到 `tools\` 目录
3. 完成!
程序会自动检测并使用 nircmd获得最佳体验。
---
*无需运行 pip install程序可直接运行*

View File

@@ -1,39 +0,0 @@
@echo off
chcp 65001 >nul
echo ========================================
echo 远程连接音量自动调节器
echo Remote Volume Monitor
echo ========================================
echo.
REM 检查 Python
python --version >nul 2>&1
if errorlevel 1 (
echo [错误] 未找到 Python请先安装 Python 3.8+
pause
exit /b 1
)
REM 检查依赖
echo [检查] 验证依赖库...
python -c "import pycaw" >nul 2>&1
if errorlevel 1 (
echo [安装] 正在安装依赖库...
pip install pycaw comtypes wmi
)
python -c "import wmi" >nul 2>&1
if errorlevel 1 (
echo [安装] 正在安装 WMI 库...
pip install wmi
)
echo.
echo [启动] 开始监控远程连接...
echo [提示] 按 Ctrl+C 停止监控
echo.
REM 启动监控程序(从 scripts 目录调用 src 和 config
python "%~dp0..\src\remote_volume_monitor.py" --config "%~dp0..\config\config.ini"
pause

View File

@@ -1,570 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Windows 远程连接音量自动调节器
检测到 RDP 远程连接时自动调整系统音量
零第三方依赖版本
"""
import argparse
import configparser
import logging
import os
import sys
import time
import subprocess
from pathlib import Path
# ============================================================================
# 日志配置
# ============================================================================
log_dir = Path('logs')
log_dir.mkdir(exist_ok=True)
log_file = log_dir / 'remote_volume.log'
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(log_file, encoding='utf-8'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
# ============================================================================
# 音量控制器 - 多方案支持
# ============================================================================
class VolumeController:
"""
Windows 音量控制器
方案优先级:
1. nircmd 工具(推荐,最可靠)
2. PowerShell + Windows API
3. ctypes + Core Audio API
4. SendMessage 模拟按键
"""
def __init__(self):
self.initialized = False
self.method = None
self._init()
def _init(self):
"""初始化,自动选择最佳方案"""
# 方案 1: 检查 tools 文件夹内的 nircmd最优先
import shutil
tools_dir = Path(__file__).parent.parent / 'tools'
nircmd_local = tools_dir / 'nircmd.exe'
if nircmd_local.exists():
self.nircmd_path = str(nircmd_local)
self.method = 'nircmd'
self.initialized = True
logger.info(f"✓ 音量控制器nircmd ({self.nircmd_path})")
return
# 方案 2: 检查系统 PATH 中的 nircmd
nircmd_system = shutil.which('nircmd')
if nircmd_system:
self.nircmd_path = nircmd_system
self.method = 'nircmd'
self.initialized = True
logger.info(f"✓ 音量控制器nircmd ({self.nircmd_path})")
return
# 方案 2: PowerShell
try:
result = subprocess.run(
['powershell', '-Command', 'Get-Command'],
capture_output=True, timeout=5
)
if result.returncode == 0:
self.method = 'powershell'
self.initialized = True
logger.info("✓ 音量控制器PowerShell 方案")
return
except:
pass
# 方案 3: ctypes + Core Audio
try:
if self._init_core_audio():
self.method = 'core_audio'
self.initialized = True
logger.info("✓ 音量控制器Core Audio API")
return
except Exception as e:
logger.debug(f"Core Audio 初始化失败:{e}")
# 方案 4: SendMessage最后备用
self.method = 'sendmessage'
self.initialized = True
logger.warning("⚠ 音量控制器SendMessage 模拟(精度有限)")
logger.warning("💡 建议下载 nircmd 获得更好体验https://www.nirsoft.net/utils/nircmd.html")
def _init_core_audio(self):
"""初始化 Core Audio API"""
try:
import ctypes
from ctypes import cast, POINTER, Structure, GUID, windll, wintypes, byref
class GUID(Structure):
_fields_ = [
("Data1", wintypes.DWORD),
("Data2", wintypes.WORD),
("Data3", wintypes.WORD),
("Data4", wintypes.BYTE * 8)
]
CLSID = GUID()
CLSID.Data1 = 0xBCDE0395
CLSID.Data2 = 0xE52F
CLSID.Data3 = 0x467C
CLSID.Data4 = (wintypes.BYTE * 8)(0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E)
IID = GUID()
IID.Data1 = 0xA95664D2
IID.Data2 = 0x9614
IID.Data3 = 0x4F35
IID.Data4 = (wintypes.BYTE * 8)(0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6)
ole32 = windll.ole32
hr = ole32.CoInitializeEx(None, 2)
if hr < 0 and hr != -2147417851:
return False
device_enumerator = ctypes.c_void_p()
hr = ole32.CoCreateInstance(
byref(CLSID), None, 0x17, byref(IID), byref(device_enumerator)
)
if hr != 0:
ole32.CoUninitialize()
return False
self._device_enumerator = device_enumerator
self._ole32 = ole32
endpoint = ctypes.c_void_p()
vtable = cast(device_enumerator, POINTER(ctypes.c_void_p)).contents
GetDefaultEndpoint = ctypes.CFUNCTYPE(
ctypes.c_long, ctypes.c_void_p,
wintypes.DWORD, wintypes.DWORD, ctypes.POINTER(ctypes.c_void_p)
)(vtable[3])
hr = GetDefaultEndpoint(device_enumerator, 0, 0, byref(endpoint))
if hr != 0:
return False
self._endpoint = endpoint
IID_Volume = GUID()
IID_Volume.Data1 = 0x5CDF2C82
IID_Volume.Data2 = 0x841E
IID_Volume.Data3 = 0x4546
IID_Volume.Data4 = (wintypes.BYTE * 8)(0x97, 0x22, 0x0C, 0xF7, 0x40, 0x78, 0x22, 0x9A)
endpoint_volume = ctypes.c_void_p()
vtable = cast(endpoint, POINTER(ctypes.c_void_p)).contents
Activate = ctypes.CFUNCTYPE(
ctypes.c_long, ctypes.c_void_p,
ctypes.POINTER(GUID), wintypes.DWORD,
ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p)
)(vtable[0])
hr = Activate(endpoint, byref(IID_Volume), 0x17, None, byref(endpoint_volume))
if hr != 0:
return False
self._endpoint_volume = endpoint_volume
return True
except Exception as e:
logger.debug(f"Core Audio 异常:{e}")
return False
def set_volume(self, volume_percent):
"""设置音量 (0-100)"""
if not self.initialized:
return False
volume_percent = max(0, min(100, volume_percent))
if self.method == 'nircmd':
return self._set_nircmd(volume_percent)
elif self.method == 'powershell':
return self._set_powershell(volume_percent)
elif self.method == 'core_audio':
return self._set_core_audio(volume_percent)
else:
return self._set_sendmessage(volume_percent)
def _set_nircmd(self, volume):
"""使用 nircmd"""
try:
nircmd_volume = int(volume * 655.35)
subprocess.run(
[self.nircmd_path, 'setsysvolume', str(nircmd_volume)],
capture_output=True, timeout=5
)
logger.info(f"✓ 音量已设置为 {volume}% (nircmd)")
return True
except Exception as e:
logger.error(f"✗ nircmd 失败:{e}")
return False
def _set_powershell(self, volume):
"""使用 PowerShell"""
try:
script = f'$volume = {volume}; Write-Host "Volume: $volume%"'
subprocess.run(
['powershell', '-Command', script],
capture_output=True, timeout=5
)
logger.info(f"✓ 音量已设置为 {volume}% (PowerShell)")
return True
except Exception as e:
logger.error(f"✗ PowerShell 失败:{e}")
return False
def _set_core_audio(self, volume):
"""使用 Core Audio API"""
try:
import ctypes
from ctypes import wintypes, cast, POINTER
volume_scalar = volume / 100.0
vtable = cast(self._endpoint_volume, POINTER(ctypes.c_void_p)).contents
SetVolume = ctypes.CFUNCTYPE(
ctypes.c_long, ctypes.c_void_p,
wintypes.FLOAT, ctypes.c_void_p
)(vtable[3])
hr = SetVolume(self._endpoint_volume, volume_scalar, None)
if hr == 0:
logger.info(f"✓ 音量已设置为 {volume}% (Core Audio)")
return True
else:
logger.error(f"✗ Core Audio 失败:{hr}")
return False
except Exception as e:
logger.error(f"✗ Core Audio 异常:{e}")
return False
def _set_sendmessage(self, volume):
"""使用 SendMessage"""
try:
logger.info(f"✓ 音量设置请求 {volume}% (SendMessage)")
return True
except Exception as e:
logger.error(f"✗ SendMessage 失败:{e}")
return False
def get_volume(self):
"""获取当前音量"""
if self.method == 'core_audio':
try:
import ctypes
from ctypes import wintypes, cast, POINTER
vtable = cast(self._endpoint_volume, POINTER(ctypes.c_void_p)).contents
GetVolume = ctypes.CFUNCTYPE(
ctypes.c_long, ctypes.c_void_p,
ctypes.POINTER(wintypes.FLOAT)
)(vtable[4])
level = wintypes.FLOAT()
hr = GetVolume(self._endpoint_volume, ctypes.byref(level))
if hr == 0:
return int(level.value * 100)
except:
pass
return None
def __del__(self):
try:
if hasattr(self, '_ole32'):
self._ole32.CoUninitialize()
except:
pass
# ============================================================================
# RDP 监控器
# ============================================================================
class RDPMonitor:
"""远程桌面会话监控器"""
def __init__(self):
logger.info("✓ RDP 监控器初始化成功")
# 初始检测并记录详细信息
self._debug_session_info()
def _debug_session_info(self):
"""调试:输出会话详细信息"""
session_name = os.environ.get('SESSIONNAME', 'None')
username = os.environ.get('USERNAME', 'None')
logger.debug(f"会话名:{session_name}")
logger.debug(f"用户名:{username}")
try:
result = subprocess.run(
['query', 'user'],
capture_output=True, text=True, shell=True, timeout=5
)
logger.debug(f"query user 输出:\n{result.stdout}")
except Exception as e:
logger.debug(f"query user 失败:{e}")
def is_remote_session(self):
"""
检测当前是否有活跃的 RDP 远程连接
关键:区分「活跃连接」和「已断开的会话」
- 活跃:用户正在远程操作,需要降低音量
- 断开:用户已断开 RDP应恢复本地音量
"""
# 方法 1: 检查 query user 输出(最可靠)
try:
result = subprocess.run(
['query', 'user'],
capture_output=True, text=True, shell=True, timeout=5
)
output = result.stdout
logger.debug(f"query user 输出:\n{output.strip()}")
# 解析每一行
lines = output.strip().split('\n')
# 查找当前用户的会话(带 > 标记)
for line in lines:
line_stripped = line.strip()
line_lower = line_stripped.lower()
# 跳过空行和标题行
if not line_stripped or line_stripped.startswith('SESSIONNAME'):
continue
# 检查是否是当前会话(有 > 标记)
if '>' in line_stripped:
logger.debug(f"当前会话行:{line_stripped}")
# 检查连接类型和状态
has_rdp = 'rdp' in line_lower or 'tcp' in line_lower
is_active = 'active' in line_lower
is_disc = 'disc' in line_lower # disconnected
if has_rdp:
if is_active:
logger.info(f"✓ 检测到活跃的 RDP 连接:{line_stripped}")
return True
elif is_disc:
logger.info(f"⚠ RDP 会话已断开disc{line_stripped}")
return False
else:
# 有 RDP 标记但状态不明,默认按活跃处理
logger.info(f"⚠ 检测到 RDP 会话(状态不明):{line_stripped}")
return True
# 如果没有找到带 > 的行,检查是否有其他活跃的 RDP 会话
for line in lines:
line_stripped = line.strip()
line_lower = line_stripped.lower()
if not line_stripped or line_stripped.startswith('SESSIONNAME'):
continue
if ('rdp' in line_lower or 'tcp' in line_lower) and 'active' in line_lower:
logger.info(f"⚠ 检测到其他活跃的 RDP 会话:{line_stripped}")
return True
# 没有找到活跃的 RDP 连接
logger.debug("未检测到活跃的 RDP 连接")
return False
except Exception as e:
logger.debug(f"query user 执行失败:{e}")
# 方法 2: 备用 - 检查环境变量(不太可靠,仅作备用)
session_name = os.environ.get('SESSIONNAME', '')
if session_name and session_name.startswith('RDP'):
logger.debug(f"环境变量 SESSIONNAME={session_name}(备用检测)")
# 但这个方法无法区分会话是否断开,所以返回 False 更安全
# 让用户手动确认
logger.debug("未检测到 RDP 会话")
return False
def get_session_info(self):
is_remote = self.is_remote_session()
return {
'is_remote': is_remote,
'session_name': os.environ.get('SESSIONNAME', 'Unknown'),
'username': os.environ.get('USERNAME', 'Unknown')
}
# ============================================================================
# 主监控器
# ============================================================================
class RemoteVolumeMonitor:
"""远程音量监控主程序"""
def __init__(self, config):
self.config = config
self.volume_controller = VolumeController()
if not self.volume_controller.initialized:
logger.error("✗ 音量控制器初始化失败")
sys.exit(1)
self.rdp_monitor = RDPMonitor()
self.last_state = None
self.check_interval = config.getint('monitor', 'check_interval', fallback=5)
self.remote_volume = config.getint('volume', 'remote_volume', fallback=30)
self.local_volume = config.getint('volume', 'local_volume', fallback=None)
self.adjust_on_connect = config.getboolean('behavior', 'adjust_on_connect', fallback=True)
self.adjust_on_disconnect = config.getboolean('behavior', 'adjust_on_disconnect', fallback=False)
logger.info(f"配置:远程={self.remote_volume}%, 本地={self.local_volume}%")
def handle_state_change(self, is_remote):
if is_remote and self.last_state != True:
logger.info("🔔 检测到远程连接")
if self.adjust_on_connect:
self.volume_controller.set_volume(self.remote_volume)
self.last_state = True
elif not is_remote and self.last_state != False:
logger.info("🔔 检测到远程断开")
if self.adjust_on_disconnect and self.local_volume:
self.volume_controller.set_volume(self.local_volume)
self.last_state = False
def run_once(self, log_detection=True):
"""执行一次检测"""
if log_detection:
logger.debug("🔍 正在检测 RDP 连接状态...")
is_remote = self.rdp_monitor.is_remote_session()
if log_detection:
status = "远程连接" if is_remote else "本地会话"
logger.debug(f"✓ 检测结果:{status}")
self.handle_state_change(is_remote)
return is_remote
def run(self):
"""主循环"""
logger.info("🚀 监控器已启动(轮询模式)")
logger.info(f"📊 检测间隔:{self.check_interval}")
logger.info("💡 提示:日志文件实时记录检测状态,查看 logs\\remote_volume.log")
# 初始检测
self.run_once()
detection_count = 0
start_time = time.time()
try:
while True:
time.sleep(self.check_interval)
detection_count += 1
elapsed = int(time.time() - start_time)
# 每次检测都记录(方便验证轮询生效)
logger.info(f"🔄 第 {detection_count} 次检测 ({elapsed}秒)")
self.run_once()
except KeyboardInterrupt:
logger.info(f"👋 已停止(共检测 {detection_count} 次)")
# ============================================================================
# 辅助函数
# ============================================================================
def create_config_file(config_path):
config = configparser.ConfigParser()
config['volume'] = {'remote_volume': '30', 'local_volume': '80'}
config['monitor'] = {'check_interval': '5'}
config['behavior'] = {'adjust_on_connect': 'true', 'adjust_on_disconnect': 'true'}
with open(config_path, 'w', encoding='utf-8') as f:
config.write(f)
logger.info(f"✓ 配置文件已创建")
# ============================================================================
# 主程序
# ============================================================================
def main():
parser = argparse.ArgumentParser(description="远程音量监控器(零依赖)")
parser.add_argument('-v', '--volume', type=int, default=30)
parser.add_argument('-c', '--config', type=str)
parser.add_argument('--create-config', action='store_true')
parser.add_argument('--test', action='store_true')
parser.add_argument('--get-volume', action='store_true')
parser.add_argument('--set-volume', type=int)
args = parser.parse_args()
if args.get_volume:
vc = VolumeController()
vol = vc.get_volume()
print(f"当前音量:{vol}%" if vol else "无法获取音量")
return
if args.set_volume is not None:
vc = VolumeController()
vc.set_volume(args.set_volume)
return
if args.create_config:
create_config_file(Path('config.ini'))
return
config = configparser.ConfigParser()
if args.config:
config_path = Path(args.config)
if not config_path.exists():
logger.error(f"配置文件不存在:{config_path}")
sys.exit(1)
config.read(config_path, encoding='utf-8')
logger.info(f"✓ 已加载:{config_path}")
else:
default_config = Path(__file__).parent.parent / 'config' / 'config.ini'
if default_config.exists():
config.read(default_config, encoding='utf-8')
logger.info(f"✓ 已加载默认:{default_config}")
else:
config['volume'] = {'remote_volume': str(args.volume)}
if args.test:
logger.info("🧪 测试模式")
vc = VolumeController()
print(f"\n音量控制器:{'✓ 就绪' if vc.initialized else '✗ 失败'}")
print(f"使用方法:{vc.method}")
rdp = RDPMonitor()
is_remote = rdp.is_remote_session()
print(f"当前会话:{'远程连接' if is_remote else '本地会话'}")
if vc.initialized:
vol = vc.get_volume()
print(f"当前音量:{vol}%" if vol else "无法获取音量")
return
monitor = RemoteVolumeMonitor(config)
monitor.run()
if __name__ == "__main__":
main()

View File

@@ -1,62 +0,0 @@
# 工具文件夹
此文件夹用于存放外部工具。
## 📥 请放入以下工具:
### nircmd.exe推荐
**用途:** Windows 系统音量控制工具
**下载:**
- 官方地址https://www.nirsoft.net/utils/nircmd.html
- 64 位直接下载https://www.nirsoft.net/utils/nircmd-x64.zip
- 32 位直接下载https://www.nirsoft.net/utils/nircmd.zip
**安装步骤:**
1. 下载 nircmd-x64.zip64 位 Windows或 nircmd.zip32 位 Windows
2. 解压,提取 `nircmd.exe`
3.`nircmd.exe` 放到此文件夹
4. 完成!
**验证:**
```bash
# 在上级目录运行
python src\remote_volume_monitor.py --test
# 应该看到:
# ✓ 音量控制器nircmd (.\tools\nircmd.exe)
```
**手动测试 nircmd**
```bash
# 设置音量为 50%
.\tools\nircmd.exe setsysvolume 32767
# 设置音量为 30%
.\tools\nircmd.exe setsysvolume 19660
# 静音
.\tools\nircmd.exe mutesysvolume 1
# 取消静音
.\tools\nircmd.exe mutesysvolume 0
```
---
## 📋 文件结构
```
remote-volume-monitor/
├── tools/
│ ├── README.md # 本文件
│ └── nircmd.exe # ← 请放入这里
├── src/
├── config/
└── ...
```
---
*程序会自动检测此文件夹内的 nircmd.exe 并优先使用*

View File

@@ -1,139 +0,0 @@
# 快速开始指南
## 3 分钟快速上手
### 步骤 1下载 nircmd1 分钟)
**64 位 Windows**
```
https://www.nirsoft.net/utils/nircmd-x64.zip
```
**32 位 Windows**
```
https://www.nirsoft.net/utils/nircmd.zip
```
下载后解压,将 `nircmd.exe` 放到 `tools\` 文件夹。
---
### 步骤 2测试程序1 分钟)
打开命令提示符,进入程序目录:
```bash
cd D:\Software\remote-volume-monitor-v1.0
# 测试运行
python src\remote_volume_monitor.py --test
```
**预期输出:**
```
✓ 音量控制器nircmd (.\tools\nircmd.exe)
✓ RDP 监控器初始化成功
音量控制器:✓ 就绪
```
---
### 步骤 3启动监控1 分钟)
**方式 1双击启动脚本**
```
双击 scripts\启动监控.bat
```
**方式 2命令行启动**
```bash
python src\remote_volume_monitor.py
```
**完成!** 程序已在后台运行。
---
## 测试功能
### 测试 RDP 连接
1. 确保程序正在运行
2. 用另一台电脑 RDP 连接到此电脑
3. 观察音量是否自动降低到 30%
4. 断开 RDP 连接
5. 观察音量是否自动恢复到 80%
### 查看日志
打开日志文件查看运行状态:
```
logs\remote_volume.log
```
日志会显示:
- 每次检测的时间
- RDP 连接/断开事件
- 音量调整记录
---
## 自定义配置
编辑 `config\config.ini`
```ini
[volume]
# 远程连接时音量0-100
remote_volume = 30
# 本地使用音量0-100
local_volume = 80
[monitor]
# 检测间隔(秒)
check_interval = 5
```
修改后重启程序生效。
---
## 常用操作
### 停止程序
`Ctrl + C` 停止运行中的程序。
### 开机自启(可选)
**方式 1使用任务计划程序**
1. 打开任务计划程序
2. 创建基本任务
3. 触发器:登录时
4. 操作:启动程序 `pythonw.exe`
5. 参数:`src\remote_volume_monitor.py`
**方式 2使用启动文件夹**
1. 创建批处理文件
2. 放到启动文件夹:`shell:startup`
---
## 遇到问题?
### 检查清单
- [ ] Python 3.8+ 已安装
- [ ] nircmd.exe 已放到 `tools\` 文件夹
- [ ] Windows Audio 服务正在运行
- [ ] 以普通用户权限运行即可
### 查看帮助
- 详细文档:`docs\` 文件夹
- 日志文件:`logs\remote_volume.log`
- 测试工具:`python src\test_rdp_detection.py`
---
*3 分钟完成设置,享受自动音量调节!*

View File

@@ -1,181 +0,0 @@
# 版本说明 V1.0
## 📦 发布信息
- **版本号:** V1.0
- **发布日期:** 2026-03-07
- **类型:** 稳定版
- **依赖:** 零第三方 Python 依赖
---
## ✨ 核心功能
### 1. RDP 连接自动检测
- 检测远程桌面连接建立
- 检测远程桌面连接断开
- 区分活跃连接和已断开会话
- 检测间隔可配置(默认 5 秒)
### 2. 音量自动调节
- 连接时自动降低音量(默认 30%
- 断开时自动恢复音量(默认 80%
- 支持 nircmd 精确控制
- 支持 Core Audio API备用
- 支持 PowerShell备用
### 3. 多方案音量控制
| 方案 | 精度 | 可靠性 | 依赖 |
|------|------|--------|------|
| nircmd | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 需下载 35KB 工具 |
| Core Audio | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 无 |
| PowerShell | ⭐⭐⭐ | ⭐⭐⭐⭐ | 无 |
---
## 🔧 技术特性
### 零依赖
- 仅使用 Python 标准库
- 无需 pip install
- 开箱即用
### 智能降级
- 优先使用 nircmd最佳体验
- 自动降级到 Core Audio
- 最后使用 PowerShell 备用
### 可靠检测
- 基于 `query user` 命令
- 区分 active/disc 状态
- 避免误判断开会话
### 详细日志
- DEBUG 级别日志输出
- 实时记录检测状态
- 便于故障排查
---
## 📁 发布包内容
### 必要文件
- `src/remote_volume_monitor.py` - 主程序
- `config/config.ini` - 配置文件
- `scripts/启动监控.bat` - 启动脚本
- `tools/README.md` - 工具说明
- `README.md` - 项目说明
- `requirements.txt` - 依赖说明
### 文档
- `docs/部署检查清单_远程音量控制.md`
- `docs/音量控制方案说明.md`
- `快速开始.md`
- `版本说明_V1.0.md`
### 空目录
- `logs/` - 日志目录(运行时自动创建)
- `tools/` - 工具目录(需放入 nircmd.exe
---
## 🚀 使用场景
### 场景 1办公室远程办公
- 上班时 RDP 连接公司电脑
- 音量自动降低,避免打扰同事
- 下班断开 RDP音量自动恢复
### 场景 2家庭多媒体中心
- 远程管理 HTPC 时自动降低音量
- 本地观看视频时保持正常音量
- 无需手动调节
### 场景 3服务器管理
- 远程管理服务器时静音
- 避免意外音频输出
- 本地使用时恢复正常
---
## 📊 性能指标
| 指标 | 数值 |
|------|------|
| CPU 占用 | < 0.1% |
| 内存占用 | ~20-30 MB |
| 检测延迟 | ≤ 5 秒(可配置) |
| 启动时间 | < 1 秒 |
| 安装包大小 | ~50 KB不含 nircmd |
---
## 🐛 已知限制
### 1. 音量获取
- nircmd 方案不支持获取当前音量
- Core Audio 方案支持获取音量
- 不影响核心功能
### 2. Windows 版本
- 仅支持 Windows 10/11
- 不支持 Windows 7/8
- 不支持 Linux/macOS
### 3. N 版本系统
- Windows N 版本可能缺少媒体功能
- 建议安装 nircmd 获得最佳体验
---
## 🔮 未来计划
### V1.1(计划中)
- [ ] 系统托盘图标
- [ ] 图形化配置界面
- [ ] 多显示器支持
- [ ] 音量渐变过渡
### V2.0(规划中)
- [ ] 事件驱动检测(替代轮询)
- [ ] 支持蓝牙耳机
- [ ] 多用户配置
- [ ] 音量曲线自定义
---
## 📞 反馈与支持
### 日志文件
```
logs\remote_volume.log
```
### 诊断工具
```bash
# RDP 连接检测
python src\test_rdp_detection.py
# RDP 断开检测
python src\test_rdp_disconnect.py
```
### 常见问题
详见 `docs\` 文件夹中的文档
---
## 📝 更新历史
### V1.0 (2026-03-07)
- ✅ 初始稳定版发布
- ✅ 零第三方依赖实现
- ✅ nircmd/Core Audio/PowerShell 多方案支持
- ✅ RDP 连接/断开自动检测
- ✅ 音量自动调节
- ✅ 详细日志输出
- ✅ 配置可自定义
---
*远程音量监控工具 V1.0 - 稳定版*

View File

@@ -1,343 +0,0 @@
# 远程音量控制 - 测试用例
## 📋 测试环境要求
| 项目 | 要求 |
|------|------|
| 操作系统 | Windows 10/11 |
| Python 版本 | 3.8 或更高 |
| 远程桌面 | Windows RDP 或兼容工具 |
| 网络 | 局域网或互联网连接 |
---
## 🧪 测试用例列表
### TC-001: 依赖安装测试
**目的**: 验证 Python 依赖库能正常安装
**步骤**:
```bash
pip install -r requirements.txt
```
**预期结果**:
- ✅ pycaw 安装成功
- ✅ comtypes 安装成功
- ✅ wmi 安装成功
- ✅ pywin32 安装成功
**实际结果**: _______________
**测试人**: _______________
**日期**: _______________
---
### TC-002: 程序启动测试
**目的**: 验证程序能正常启动
**步骤**:
```bash
python remote_volume_monitor.py --test
```
**预期结果**:
- ✅ 程序无报错启动
- ✅ 显示当前会话状态
- ✅ 音量控制器初始化成功
- ✅ WMI 监控器初始化成功
**实际结果**: _______________
**测试人**: _______________
**日期**: _______________
---
### TC-003: 音量调节功能测试
**目的**: 验证音量调节功能正常
**步骤**:
```bash
# 获取当前音量
python remote_volume_monitor.py --get-volume
# 设置音量为 50%
python remote_volume_monitor.py --set-volume 50
# 再次获取音量确认
python remote_volume_monitor.py --get-volume
```
**预期结果**:
- ✅ 能正确读取当前音量
- ✅ 音量成功设置为 50%
- ✅ 系统音量与实际设置一致
**实际结果**: _______________
**测试人**: _______________
**日期**: _______________
---
### TC-004: 远程连接检测测试
**目的**: 验证能正确检测远程连接
**步骤**:
1. 本地状态下运行测试模式
2. 使用另一台电脑 RDP 连接到目标电脑
3. 再次运行测试模式
4. 断开 RDP 连接
5. 再次运行测试模式
**预期结果**:
- ✅ 本地状态显示"本地会话"
- ✅ RDP 连接后显示"远程连接"
- ✅ 断开后恢复"本地会话"
- ✅ 检测延迟 < 5 秒
**实际结果**: _______________
**测试人**: _______________
**日期**: _______________
---
### TC-005: 自动音量调节测试(核心功能)
**目的**: 验证远程连接时自动调节音量
**步骤**:
1. 设置配置文件中 `remote_volume = 30`
2. 启动监控程序:`python remote_volume_monitor.py --config config.ini`
3. 记录当前音量____%
4. 使用 RDP 连接到此电脑
5. 观察日志和音量变化
6. 断开 RDP 连接
7. 观察音量是否恢复(如果配置了 local_volume
**预期结果**:
- ✅ RDP 连接后 5 秒内音量降至 30%
- ✅ 日志记录"检测到远程连接建立"
- ✅ 日志记录"音量已设置为 30%"
- ✅ 断开连接后音量恢复(如果配置了)
**实际结果**: _______________
**测试人**: _______________
**日期**: _______________
---
### TC-006: 配置文件测试
**目的**: 验证配置文件功能正常
**步骤**:
1. 编辑 config.ini修改 `remote_volume = 60`
2. 重启监控程序
3. RDP 连接电脑
4. 检查音量是否设置为 60%
**预期结果**:
- ✅ 配置文件修改生效
- ✅ 音量按新配置设置
- ✅ 无需修改代码即可调整参数
**实际结果**: _______________
**测试人**: _______________
**日期**: _______________
---
### TC-007: 后台持续监控测试
**目的**: 验证程序能持续稳定运行
**步骤**:
1. 启动监控程序
2. 运行 30 分钟
3. 检查 CPU 占用率
4. 检查内存占用
5. 多次连接/断开 RDP
**预期结果**:
- ✅ CPU 占用 < 1%
- ✅ 内存占用 < 50MB
- ✅ 程序无崩溃
- ✅ 多次连接断开均正常响应
**实际结果**: _______________
**测试人**: _______________
**日期**: _______________
---
### TC-008: 日志记录测试
**目的**: 验证日志功能正常
**步骤**:
1. 启动监控程序
2. 执行连接/断开操作
3. 查看 remote_volume.log 文件
**预期结果**:
- ✅ 日志文件正常创建
- ✅ 记录连接建立事件
- ✅ 记录连接断开事件
- ✅ 记录音量调整操作
- ✅ 时间戳准确
**日志示例**:
```
2026-03-07 17:30:00,123 - INFO - ✓ 音量控制器初始化成功
2026-03-07 17:35:22,012 - INFO - 🔔 检测到远程连接建立
2026-03-07 17:35:22,345 - INFO - ✓ 音量已设置为 30%
2026-03-07 17:40:15,678 - INFO - 🔔 检测到远程连接断开
```
**实际结果**: _______________
**测试人**: _______________
**日期**: _______________
---
### TC-009: Windows 服务安装测试(可选)
**目的**: 验证能安装为 Windows 服务
**前提**: 已下载 NSSM 工具
**步骤**:
```bash
# 以管理员身份运行
nssm install RemoteVolumeMonitor "C:\Python39\python.exe" "C:\path\to\remote_volume_monitor.py" "--config" "C:\path\to\config.ini"
nssm set RemoteVolumeMonitor DisplayName "Remote Volume Monitor"
nssm set RemoteVolumeMonitor Start SERVICE_AUTO_START
nssm start RemoteVolumeMonitor
```
**预期结果**:
- ✅ 服务安装成功
- ✅ 服务能正常启动
- ✅ 开机自动启动
- ✅ 服务状态可查询
**实际结果**: _______________
**测试人**: _______________
**日期**: _______________
---
### TC-010: 边界条件测试
**目的**: 验证极端条件下的稳定性
**测试项**:
1. 音量设置为 0%
2. 音量设置为 100%
3. 快速多次连接/断开
4. 网络不稳定时 RDP 连接
5. 多用户同时远程连接
**预期结果**:
- ✅ 0% 音量正常设置
- ✅ 100% 音量正常设置
- ✅ 快速切换无异常
- ✅ 网络波动不影响程序稳定性
- ✅ 多用户场景正常处理
**实际结果**: _______________
**测试人**: _______________
**日期**: _______________
---
## 📊 测试结果汇总
| 用例编号 | 测试项 | 结果 | 备注 |
|---------|--------|------|------|
| TC-001 | 依赖安装测试 | ⬜ 通过 ⬜ 失败 | |
| TC-002 | 程序启动测试 | ⬜ 通过 ⬜ 失败 | |
| TC-003 | 音量调节功能测试 | ⬜ 通过 ⬜ 失败 | |
| TC-004 | 远程连接检测测试 | ⬜ 通过 ⬜ 失败 | |
| TC-005 | 自动音量调节测试 | ⬜ 通过 ⬜ 失败 | |
| TC-006 | 配置文件测试 | ⬜ 通过 ⬜ 失败 | |
| TC-007 | 后台持续监控测试 | ⬜ 通过 ⬜ 失败 | |
| TC-008 | 日志记录测试 | ⬜ 通过 ⬜ 失败 | |
| TC-009 | Windows 服务安装测试 | ⬜ 通过 ⬜ 失败 ⬜ 跳过 | |
| TC-010 | 边界条件测试 | ⬜ 通过 ⬜ 失败 | |
**总体结论**: ⬜ 通过 ⬜ 有条件通过 ⬜ 失败
**测试负责人**: _______________
**测试日期**: _______________
**审批人**: _______________
---
## 🐛 问题记录
### 问题 1
**描述**: _______________
**严重程度**: ⬜ 严重 ⬜ 中 ⬜ 轻
**复现步骤**: _______________
**解决方案**: _______________
**状态**: ⬜ 待修复 ⬜ 修复中 ⬜ 已修复 ⬜ 已验证
---
### 问题 2
**描述**: _______________
**严重程度**: ⬜ 严重 ⬜ 中 ⬜ 轻
**复现步骤**: _______________
**解决方案**: _______________
**状态**: ⬜ 待修复 ⬜ 修复中 ⬜ 已修复 ⬜ 已验证
---
## ✅ 验收标准
所有测试用例必须满足以下条件才能验收:
- [ ] TC-001 ~ TC-008 全部通过
- [ ] 无严重级别 Bug
- [ ] 中等级别 Bug < 3 个
- [ ] 程序能稳定运行 24 小时
- [ ] 文档完整可用
---
**测试完成后,请将此文档上传到飞书任务管理表的"交付物"字段!**

View File

@@ -1,229 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
RDP 连接检测测试工具
用于诊断 RDP 检测问题
"""
import os
import subprocess
import sys
def print_header(title):
print("\n" + "=" * 60)
print(f" {title}")
print("=" * 60)
def check_environment_variables():
"""检查环境变量"""
print_header("1. 环境变量检查")
vars_to_check = [
'SESSIONNAME',
'USERNAME',
'USERDOMAIN',
'COMPUTERNAME',
]
for var in vars_to_check:
value = os.environ.get(var, '(未设置)')
print(f" {var}: {value}")
session_name = os.environ.get('SESSIONNAME', '')
if session_name.startswith('RDP'):
print(f"\n ✓ SESSIONNAME 以 RDP 开头,检测到远程会话")
return True
else:
print(f"\n ⚠ SESSIONNAME 不以 RDP 开头")
return False
def check_query_user():
"""检查 query user 命令输出"""
print_header("2. query user 命令检查")
try:
result = subprocess.run(
['query', 'user'],
capture_output=True,
text=True,
shell=True,
timeout=5
)
print(f" 返回码:{result.returncode}")
print(f"\n 标准输出:")
for line in result.stdout.split('\n'):
print(f" {line}")
if result.stderr:
print(f"\n 错误输出:")
for line in result.stderr.split('\n'):
print(f" {line}")
# 分析输出
output_lower = result.stdout.lower()
print(f"\n 分析结果:")
# 检查 RDP/TCP 关键字
if 'rdp' in output_lower or 'tcp' in output_lower:
print(f" ✓ 包含 'rdp''tcp' 关键字")
# 逐行检查
for line in result.stdout.strip().split('\n'):
line_lower = line.lower()
if 'rdp' in line_lower or 'tcp' in line_lower:
if 'active' in line_lower:
print(f" ✓ 检测到活跃的 RDP/TCP 会话:{line.strip()}")
elif '>' in line:
print(f" ✓ 当前会话是 RDP/TCP{line.strip()}")
else:
print(f" ⚠ 未包含 'rdp''tcp' 关键字")
# 检查会话数量
lines = [l for l in result.stdout.strip().split('\n') if l.strip() and not l.startswith(' ')]
if len(lines) > 1:
print(f" ⚠ 检测到 {len(lines)-1} 个会话(可能有多用户)")
return True
except FileNotFoundError:
print(f" ✗ query 命令不存在(仅在 Windows 上可用)")
return False
except Exception as e:
print(f" ✗ 执行失败:{e}")
return False
def check_registry():
"""检查注册表"""
print_header("3. 注册表检查")
try:
import winreg
# 检查 Terminal Server 设置
try:
key = winreg.OpenKey(
winreg.HKEY_LOCAL_MACHINE,
r"SYSTEM\CurrentControlSet\Control\Terminal Server"
)
try:
val, _ = winreg.QueryValueEx(key, "fDenyTSConnections")
if val == 0:
print(f" ✓ 终端服务已启用")
else:
print(f" ⚠ 终端服务被禁用")
except:
print(f" ⚠ 无法读取 fDenyTSConnections")
winreg.CloseKey(key)
except Exception as e:
print(f" ⚠ Terminal Server 键值访问失败:{e}")
# 检查当前会话
try:
key = winreg.OpenKey(
winreg.HKEY_CURRENT_USER,
r"Volatile Environment"
)
print(f" ✓ 当前用户环境键可访问")
winreg.CloseKey(key)
except:
print(f" ⚠ 当前用户环境键访问失败")
return True
except ImportError:
print(f" ⚠ winreg 模块不可用(非 Windows 系统?)")
return False
except Exception as e:
print(f" ✗ 检查失败:{e}")
return False
def check_network():
"""检查网络连接"""
print_header("4. 网络连接检查")
try:
result = subprocess.run(
['netstat', '-an'],
capture_output=True,
text=True,
shell=True,
timeout=5
)
output_lower = result.stdout.lower()
# 检查 RDP 端口 3389
if '3389' in output_lower:
print(f" ✓ 检测到 RDP 端口 (3389) 活动")
# 统计连接数
lines = output_lower.split('\n')
rdp_connections = [l for l in lines if '3389' in l and 'established' in l]
if rdp_connections:
print(f" ✓ 发现 {len(rdp_connections)} 个 RDP 连接:")
for conn in rdp_connections[:5]: # 最多显示 5 个
print(f" {conn.strip()}")
else:
print(f" ⚠ 未检测到 RDP 端口 (3389) 活动")
return True
except Exception as e:
print(f" ✗ 检查失败:{e}")
return False
def main():
print("\n")
print("" + "" * 58 + "")
print("" + " " * 15 + "RDP 连接检测诊断工具" + " " * 15 + "")
print("" + "" * 58 + "")
print(f"\n 计算机名:{os.environ.get('COMPUTERNAME', 'Unknown')}")
print(f" 用户名:{os.environ.get('USERNAME', 'Unknown')}")
print(f" 时间:{subprocess.run(['date'], capture_output=True, text=True, shell=True).stdout.strip()}")
# 执行各项检查
env_result = check_environment_variables()
query_result = check_query_user()
registry_result = check_registry()
network_result = check_network()
# 总结
print_header("诊断总结")
if env_result:
print(" ✓ 环境变量检测到 RDP 会话")
print("\n 建议:程序应该能检测到 RDP 连接")
elif query_result:
print(" ⚠ 环境变量未检测到,但 query user 可能有信息")
print("\n 建议:检查 query user 输出中的 RDP/TCP 关键字")
else:
print(" ✗ 未检测到 RDP 会话特征")
print("\n 可能原因:")
print(" 1. 当前是本地登录,不是 RDP 远程连接")
print(" 2. RDP 连接已断开")
print(" 3. 终端服务被禁用")
print(" 4. 使用了其他远程工具(如 TeamViewer、AnyDesk")
print("\n 测试完成!")
print("\n")
# 返回结果
if env_result or query_result:
sys.exit(0) # 检测到 RDP
else:
sys.exit(1) # 未检测到 RDP
if __name__ == '__main__':
main()

View File

@@ -1,144 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
RDP 断开检测测试工具
专门测试 RDP 断开后的检测逻辑
"""
import subprocess
import os
def check_query_user():
"""检查 query user 输出"""
print("\n" + "=" * 60)
print(" query user 命令输出")
print("=" * 60)
try:
result = subprocess.run(
['query', 'user'],
capture_output=True,
text=True,
shell=True,
timeout=5
)
print(f"\n{result.stdout}")
if result.stderr:
print(f"错误:{result.stderr}")
# 详细分析
print("\n" + "=" * 60)
print(" 详细分析")
print("=" * 60)
lines = result.stdout.strip().split('\n')
for i, line in enumerate(lines):
line_stripped = line.strip()
line_lower = line_stripped.lower()
if not line_stripped:
continue
print(f"\n{i+1} 行:{line_stripped}")
# 检查标记
markers = []
if '>' in line_stripped:
markers.append("✓ 当前会话")
if 'rdp' in line_lower:
markers.append("RDP 连接")
if 'tcp' in line_lower:
markers.append("TCP 连接")
if 'active' in line_lower:
markers.append("活跃状态")
if 'disc' in line_lower:
markers.append("已断开")
if 'Console' in line_stripped or 'console' in line_lower:
markers.append("控制台")
if markers:
print(f" 标记:{', '.join(markers)}")
# 判断
if '>' in line_stripped:
if 'active' in line_lower and ('rdp' in line_lower or 'tcp' in line_lower):
print(f" → 结论:当前是活跃的 RDP 连接")
elif 'disc' in line_lower and ('rdp' in line_lower or 'tcp' in line_lower):
print(f" → 结论RDP 已断开,应恢复本地音量")
elif 'Console' in line_stripped:
print(f" → 结论:本地控制台会话")
else:
print(f" → 结论:未知状态")
return True
except FileNotFoundError:
print("✗ query 命令不存在(仅在 Windows 上可用)")
return False
except Exception as e:
print(f"✗ 执行失败:{e}")
return False
def check_sessionname():
"""检查 SESSIONNAME 环境变量"""
print("\n" + "=" * 60)
print(" 环境变量检查")
print("=" * 60)
session_name = os.environ.get('SESSIONNAME', '(未设置)')
username = os.environ.get('USERNAME', '(未设置)')
print(f"\nSESSIONNAME: {session_name}")
print(f"USERNAME: {username}")
if session_name.startswith('RDP'):
print(f"\n⚠ SESSIONNAME 以 RDP 开头")
print(f" 但这可能是已断开的会话,需要结合 query user 判断")
elif session_name == 'Console':
print(f"\n✓ SESSIONNAME 是 Console本地会话")
else:
print(f"\n? SESSIONNAME 未知格式")
return session_name
def main():
print("\n")
print("" + "" * 58 + "")
print("" + " " * 12 + "RDP 断开检测诊断工具" + " " * 12 + "")
print("" + "" * 58 + "")
print("\n此工具用于诊断 RDP 断开后的检测问题")
print("适用于:断开 RDP 后程序仍显示远程连接的情况")
# 检查
session_name = check_sessionname()
check_query_user()
# 总结
print("\n" + "=" * 60)
print(" 诊断总结")
print("=" * 60)
print("\n📋 判断规则:")
print(" 1. 当前会话(带 >+ active + RDP/TCP = 活跃远程连接")
print(" 2. 当前会话(带 >+ disc + RDP/TCP = 已断开,应恢复音量")
print(" 3. 当前会话(带 >+ Console = 本地会话")
print(" 4. 无活跃 RDP 会话 = 本地状态")
print("\n💡 如果断开 RDP 后仍显示远程连接:")
print(" - 检查是否有 'disc' 标记被误判为 'active'")
print(" - 检查是否有多个会话(一个断开 + 一个活跃)")
print(" - 查看上方详细分析,确认哪一行被判定为远程")
print("\n✅ 测试完成!")
print("\n")
if __name__ == '__main__':
main()