Repository navigation
Expand file tree
/
Copy pathHonorWmi.cs
More file actions
127 lines (112 loc) · 5.04 KB
/
Copy pathHonorWmi.cs
File metadata and controls
127 lines (112 loc) · 5.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
using System.Management;
namespace HonorPCHelper;
internal sealed class HonorWmiCommandException(int errorCode, string message) : InvalidOperationException(message)
{
internal int ErrorCode { get; } = errorCode;
}
/// <summary>
/// Reusable HONOR BIOS WMI connection. Connecting to the scope and locating the
/// OemWMIMethod instance is expensive, so a single session can be shared across
/// several commands (e.g. one sensor refresh) instead of reconnecting per call.
/// </summary>
internal sealed class HonorWmiSession : IDisposable
{
// Экземпляров OemWMIMethod бывает два (HWMI_0 и HWMI_1), а порядок перечисления
// WMI ничем не гарантирован. PC Manager обращается к HWMI_0.
private const string PreferredInstance = "HWMI_0";
private ManagementObject? _instance;
/// <summary>Выбирает HWMI_0, а если его нет - первый найденный экземпляр.</summary>
internal static ManagementObject? SelectInstance(IEnumerable<ManagementObject> instances)
{
ManagementObject? first = null;
foreach (var instance in instances)
{
if (instance["InstanceName"] is string name
&& name.EndsWith(PreferredInstance, StringComparison.OrdinalIgnoreCase))
return instance;
first ??= instance;
}
return first;
}
private ManagementObject GetInstance()
{
if (_instance is not null)
return _instance;
var scope = new ManagementScope(@"\\.\root\wmi");
scope.Options.EnablePrivileges = true;
scope.Connect();
using var searcher = new ManagementObjectSearcher(scope, new ObjectQuery("SELECT * FROM OemWMIMethod"));
using var instances = searcher.Get();
return _instance = SelectInstance(instances.Cast<ManagementObject>())
?? throw new InvalidOperationException(L.T(
"Интерфейс HONOR BIOS WMI не найден.",
"HONOR BIOS WMI interface was not found.",
"未找到 HONOR BIOS WMI 接口。"));
}
internal byte[] Call(ulong command)
{
Exception? lastError = null;
for (var attempt = 0; attempt < 2; attempt++)
{
try
{
var instance = GetInstance();
using var parameters = instance.GetMethodParameters("OemWMIfun");
var input = new byte[64];
BitConverter.GetBytes(command).CopyTo(input, 0);
parameters["u8Input"] = input;
using var result = instance.InvokeMethod("OemWMIfun", parameters, null);
var output = (byte[]?)result?["u8Output"]
?? throw new InvalidOperationException(L.T(
"BIOS не вернул ответ.",
"BIOS did not return a response.",
"BIOS 未返回响应。"));
if (output.Length > 0 && output[0] == 0)
return output;
// BIOS ответил отказом - команда дошла, повторять её незачем.
var errorCode = output.Length > 0 ? output[0] : 255;
lastError = new HonorWmiCommandException(errorCode, L.T(
$"BIOS отклонил команду (код {errorCode}).",
$"BIOS rejected the command (code {errorCode}).",
$"BIOS 拒绝了该命令(代码 {errorCode})。"));
break;
}
catch (UnauthorizedAccessException exception)
{
throw new InvalidOperationException(L.T(
"Для обращения к HONOR BIOS нужны права администратора.",
"Administrator privileges are required to access HONOR BIOS.",
"访问 HONOR BIOS 需要管理员权限。"), exception);
}
catch (ManagementException exception)
{
lastError = new InvalidOperationException(L.T(
"Ошибка HONOR BIOS WMI: ",
"HONOR BIOS WMI error: ",
"HONOR BIOS WMI 错误:") + exception.Message, exception);
// Drop the cached instance so the next attempt reconnects.
_instance?.Dispose();
_instance = null;
}
}
var finalError = lastError ?? new InvalidOperationException(L.T(
"Команда BIOS не выполнена.",
"BIOS command was not executed.",
"BIOS 命令未执行。"));
AppLog.Error($"HONOR WMI command 0x{command:X} failed", finalError);
throw finalError;
}
public void Dispose()
{
_instance?.Dispose();
_instance = null;
}
}
internal static class HonorWmi
{
internal static byte[] Call(ulong command)
{
using var session = new HonorWmiSession();
return session.Call(command);
}
}