-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPdh.cs
More file actions
143 lines (121 loc) · 4.83 KB
/
Copy pathPdh.cs
File metadata and controls
143 lines (121 loc) · 4.83 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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace CoreTempGPU
{
/// <summary>PDH (Performance Data Helper) GPU counters — the universal Windows source.</summary>
internal static class Pdh
{
private const int ERROR_SUCCESS = 0;
private const uint PDH_FMT_DOUBLE = 0x00000200;
private const uint PDH_FMT_NOCAP100 = 0x00008000;
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
private static extern int PdhOpenQueryW(IntPtr dataSource, IntPtr userData, out IntPtr query);
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
private static extern int PdhCloseQuery(IntPtr query);
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
private static extern int PdhAddEnglishCounterW(IntPtr query, string counterPath, IntPtr userData, out IntPtr counter);
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
private static extern int PdhRemoveCounter(IntPtr counter);
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
private static extern int PdhCollectQueryData(IntPtr query);
[DllImport("pdh.dll", CharSet = CharSet.Unicode)]
private static extern int PdhGetFormattedCounterValue(IntPtr counter, uint format, out uint type, out CounterValue value);
[StructLayout(LayoutKind.Sequential)]
private struct CounterValue
{
public int CStatus;
public double data;
}
/// <summary>One live PDH counter bound to a query.</summary>
public sealed class Counter : IDisposable
{
private readonly IntPtr _query;
private IntPtr _handle;
public readonly string Path;
public bool Valid { get; private set; }
public Counter(IntPtr query, string path)
{
_query = query;
Path = path;
}
public bool Add()
{
int rc = PdhAddEnglishCounterW(_query, Path, IntPtr.Zero, out _handle);
Valid = (rc == ERROR_SUCCESS);
return Valid;
}
/// <summary>Read the current value. Returns false when no data is available.</summary>
public bool TryRead(out double value)
{
value = 0;
if (!Valid) return false;
CounterValue v;
uint type;
int rc = PdhGetFormattedCounterValue(_handle, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, out type, out v);
if (rc != ERROR_SUCCESS || v.CStatus != ERROR_SUCCESS) return false;
value = v.data;
return true;
}
public void Dispose()
{
if (_handle != IntPtr.Zero) PdhRemoveCounter(_handle);
_handle = IntPtr.Zero;
}
}
/// <summary>Starts a query and registers the given counters. Disposal closes the query.</summary>
public static QueryHandle OpenQuery(IEnumerable<string> paths)
{
IntPtr q;
if (PdhOpenQueryW(IntPtr.Zero, IntPtr.Zero, out q) != ERROR_SUCCESS) return null;
try
{
var query = new QueryHandle(q);
foreach (var p in paths) query.Add(p);
return query;
}
catch
{
PdhCloseQuery(q);
throw;
}
}
public sealed class QueryHandle : IDisposable
{
private IntPtr _query;
public readonly List<Counter> Counters = new List<Counter>();
public QueryHandle(IntPtr query) { _query = query; }
public Counter Add(string path)
{
var c = new Counter(_query, path);
c.Add();
Counters.Add(c);
return c;
}
/// <summary>Collect once. Call twice with a gap between for rate counters to yield data.</summary>
public void Collect()
{
if (_query != IntPtr.Zero) PdhCollectQueryData(_query);
}
public void Dispose()
{
foreach (var c in Counters) c.Dispose();
Counters.Clear();
if (_query != IntPtr.Zero) PdhCloseQuery(_query);
_query = IntPtr.Zero;
}
}
/// <summary>
/// DXGI adapter enumeration is intentionally omitted — incomplete COM vtables
/// crash the Core Temp host process. Adapter names come from NVML when available.
/// </summary>
public static long GetPrimaryDisplayLuid()
{
return 0;
}
public static List<Tuple<long, string>> EnumerateAdapters()
{
return new List<Tuple<long, string>>();
}
}
}