1 // =========================================================================
2 //
3 // INTEL CONFIDENTIAL
4 // Copyright 2005 - 2015
5 // Intel Corporation All Rights Reserved.
6 //
7 // =========================================================================
8 // The source code contained or described herein and all documents
9 // related to the source code ("Material") are owned by Intel Corporation
10 // or its suppliers or licensors. Title to the Material remains with
11 // Intel Corporation or its suppliers and licensors. The Material contains
12 // trade secrets and proprietary and confidential information of Intel or
13 // its suppliers and licensors. The Material is protected by worldwide
14 // copyright and trade secret laws and treaty provisions. No part of the
15 // Material may be used, copied, reproduced, modified, published, uploaded,
16 // posted, transmitted, distributed, or disclosed in any way without Intel’s
17 // prior express written permission.
18 //
19 // No license under any patent, copyright, trade secret or other intellectual
20 // property right is granted to or conferred upon you by disclosure or
21 // delivery of the Materials, either expressly, by implication, inducement,
22 // estoppel or otherwise. Any license under such intellectual property rights
23 // must be express and approved by Intel in writing.
24 // ==========================================================================
25
26 using System;
27 using System.Collections.Generic;
28 using System.ComponentModel;
29 using System.IO;
30 using System.Linq;
31 using System.Runtime.InteropServices;
32 using System.Text;
33 using System.Text.RegularExpressions;
34 using Microsoft.Win32;
35
36 namespace Intel.Tools.DeviceManager
37 {
38 internal static class DeviceQuery
39 {
40 #region GetAllDevices
41 internal static DeviceList GetAllDevices()
42 {
43 int memberIndex = 0;
44 SP_DEVINFO_DATA devInfoData;
(1) Event new_resource: |
Created a new object of type "Intel.Tools.DeviceManager.DeviceList", which implements "System.IDisposable". [details] |
(2) Event var_assign: |
Assigning: "deviceList" = resource returned from "new Intel.Tools.DeviceManager.DeviceList()". |
Also see events: |
[noescape][leaked_resource] |
45 var deviceList = new DeviceList();
46
(3) Event cond_true: |
Condition "true", taking true branch. |
47 while (true)
48 {
49 devInfoData = SP_DEVINFO_DATA.Empty();
50
(4) Event noescape: |
Resource "deviceList" is not closed or saved in "DeviceInfoSet.get". [details] |
(5) Event throw_uncaught: |
Throwing "System.Exception" from call to "DeviceInfoSet.get"; exiting method with uncaught exception. [details] |
(6) Event leaked_resource: |
Variable "deviceList" going out of scope leaks the resource it refers to. |
Also see events: |
[new_resource][var_assign] |
51 if (!Win32Interop.SetupDiEnumDeviceInfo(deviceList.DeviceInfoSet, memberIndex, ref devInfoData))
52 {
53 var error = Marshal.GetLastWin32Error();
54
55 if (error == Win32Error.NoMoreItems)
56 break;
57 else
58 {
59 deviceList.Dispose();
60 throw new Win32Exception(error, "An error occurred when searching for drivers.");
61 }
62 }
63 else
64 {
65 deviceList.Add(new Device(deviceList, devInfoData));
66 }
67
68 memberIndex++;
69 }
70
71 return deviceList;
72 }
73 #endregion
74
75 #region Get Properties
76 #region Extensions
77 internal static object GetProperty(this Device device, DeviceRegistryProperty flags)
78 {
79 var devInfoData = device.DevInfoData;
80
81 object obj = GetProperty(device.DeviceInfoSet, ref devInfoData, (uint)flags);
82
83 device.DevInfoData = devInfoData;
84
85 return obj;
86 }
87
88 internal static int GetPropertyInt(this Device device, DeviceRegistryProperty flags)
89 {
90 var devInfoData = device.DevInfoData;
91
92 int value = GetPropertyInt(device.DeviceInfoSet, ref devInfoData, (uint)flags);
93
94 device.DevInfoData = devInfoData;
95
96 return value;
97 }
98
99 internal static string GetPropertyString(this Device device, DeviceRegistryProperty flags)
100 {
101 var devInfoData = device.DevInfoData;
102
103 string value = GetPropertyString(device.DeviceInfoSet, ref devInfoData, (uint)flags);
104
105 device.DevInfoData = devInfoData;
106
107 return value;
108 }
109
110 /// <summary>
111 /// Gets the RegistryKey to the driver information for the given device.
112 /// </summary>
113 private static RegistryKey GetDriverKey(this Device device, bool writable = false)
114 {
115 if (!_string.IsNullOrWhiteSpace(device.Driver))
116 {
117 using (var hklm = Registry.LocalMachine)
118 {
119 return hklm.OpenSubKey(@"System\CurrentControlSet\Control\Class\" + device.Driver, writable);
120 }
121 }
122 else return null;
123 }
124
125 internal static string GetProviderName(this Device device)
126 {
127 using (var key = device.GetDriverKey())
128 {
129 return key == null ? string.Empty : key.GetValue("ProviderName", string.Empty) as string;
130 }
131 }
132
133 internal static string GetInfPath(this Device device)
134 {
135 using (var key = device.GetDriverKey())
136 {
137 if (key == null)
138 {
139 return string.Empty;
140 }
141 else
142 {
143 string infPath = key.GetValue("InfPath", string.Empty) as string;
144
145 if (!_string.IsNullOrWhiteSpace(infPath))
146 {
147 return _Path.Combine(_Path.GetWindowsDirectory(), "INF", infPath);
148
149 }
150 else return string.Empty;
151 }
152 }
153 }
154
155 internal static string GetPackageInfoName(this Device device)
156 {
157 string infPath = device.GetInfPath();
158
159 if (File.Exists(infPath))
160 {
161 return GetPackageInfoName(infPath);
162 }
163 else
164 {
165 return string.Empty;
166 }
167 }
168
169 private static string GetPackageInfoName(string infPath)
170 {
171 string packageInfoName = string.Empty;
172
173 using (var reader = new StreamReader(infPath))
174 {
175 string line = reader.ReadLine();;
176 string sectionPattern = @"^\s*\[\s*(.+)\s*\]\s*$";
177 string packageInfoSectionPattern = @"^\s*\[\s*PackageInfo\s*\]\s*$";
178 string nameFieldPattern = @"^\s*Name\s*=\s*(.+)\s*$";
179
180 //Search the file until we find the PackageInfo section.
181 while (!reader.EndOfStream)
182 {
183 line = reader.ReadLine();
184
185 //If we found the PackageInfo section...
186 if (Regex.IsMatch(line, packageInfoSectionPattern, RegexOptions.IgnoreCase))
187 {
188 //...then break.
189 break;
190 }
191 }
192
193 //Continue searching until we find the next section or the Name field.
194 while (!reader.EndOfStream)
195 {
196 line = reader.ReadLine();
197
198 //If we found the Name field...
199 if (Regex.IsMatch(line, nameFieldPattern, RegexOptions.IgnoreCase))
200 {
201 //...then get the value of that field so we can return it.
202 packageInfoName = Regex.Match(line, nameFieldPattern, RegexOptions.IgnoreCase).Groups[1].Value;
203 break;
204 }
205 //...else if we found the next section...
206 else if (Regex.IsMatch(line, sectionPattern))
207 {
208 //...then break.
209 break;
210 }
211 //...otherwise, continue searching.
212 }
213
214 reader.Close();
215 }
216
217 return packageInfoName;
218 }
219 #endregion
220
221 internal static object GetProperty(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA devInfoData, uint flags)
222 {
223 IntPtr buffer = IntPtr.Zero;
224 int bufferSize = 0;
225 uint regType = 0, requiredSize = 0;
226
227 //Find the correct amount of memory required for the buffer.
228 if (!Win32Interop.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, flags, out regType, buffer, bufferSize, out requiredSize))
229 {
230 switch ((RegistryValueKind)regType)
231 {
232 case RegistryValueKind.DWord:
233 return GetPropertyInt(deviceInfoSet, ref devInfoData, flags);
234
235 case RegistryValueKind.Binary: //break;
236 case RegistryValueKind.ExpandString: //break;
237 case RegistryValueKind.MultiString: //break;
238 //case RegistryValueKind.None: //break; // Not available in .Net 3.5
239 case RegistryValueKind.QWord: //break;
240 case RegistryValueKind.Unknown: //break;
241 case RegistryValueKind.String:
242 return GetPropertyString(deviceInfoSet, ref devInfoData, flags);
243
244 default:
245 break;
246 }
247 }
248
249 return string.Empty;
250 }
251
252 internal static int GetPropertyInt(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA devInfoData, uint flags)
253 {
254 byte[] buffer = null;// new byte[0];
255 int bufferSize = 0;
256 uint regType = 0, requiredSize = 0;
257
258 //Find the correct amount of memory required for the buffer.
259 unsafe { fixed (byte* bufferPtr = buffer) {
260 IntPtr bufferIntPtr = new IntPtr(bufferPtr);
261 if (!Win32Interop.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, flags, out regType, bufferIntPtr, bufferSize, out requiredSize))
262 {
263 int error = Marshal.GetLastWin32Error();
264
265 switch (error)
266 {
267 case Win32Error.InsufficientBuffer:
268 //Do nothing.
269 break;
270 case Win32Error.InvalidData:
271 //Return 0
272 return 0;
273 default:
274 //Throw an exception.
275 throw new Win32Exception(error);
276 }
277 }
278 }}
279
280 //Allocate the correct amount of memory for the buffer.
281 bufferSize = (int)requiredSize;
282 buffer = new byte[bufferSize];
283 unsafe { fixed (byte* bufferPtr = buffer) {
284 IntPtr bufferIntPtr = new IntPtr(bufferPtr);
285 try
286 {
287 //Populate the buffer.
288 if (Win32Interop.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, flags, out regType, bufferIntPtr, bufferSize, out requiredSize))
289 {
290 return BitConverter.ToInt32(buffer, 0);
291 }
292 else { throw new Win32Exception(Marshal.GetLastWin32Error()); }
293 }
294 catch { throw; }
295 }}
296 }
297
298 internal static string GetPropertyString(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA devInfoData, uint flags)
299 {
300 IntPtr buffer = IntPtr.Zero;
301 int bufferSize = 0;
302 uint regType = 0, requiredSize = 0;
303
304 //Find the correct amount of memory required for the buffer.
305 if (!Win32Interop.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, flags, out regType, buffer, bufferSize, out requiredSize))
306 {
307 if (regType == (int)RegistryValueKind.Unknown)
308 {
309 return null;
310 }
311 else if (regType != (int)RegistryValueKind.String)
312 {
313 return string.Format(" ~~~~~ {0} ~~~~~", (RegistryValueKind)regType);
314 }
315
316 int error = Marshal.GetLastWin32Error();
317
318 switch (error)
319 {
320 case Win32Error.InsufficientBuffer:
321 //Do nothing.
322 break;
323 case Win32Error.InvalidData:
324 //Return an empty string.
325 return string.Empty;
326 default:
327 //Throw an exception.
328 throw new Win32Exception(error);
329 }
330 }
331
332 //Allocate the correct amount of memory for the buffer.
333 bufferSize = (int)requiredSize;
334 buffer = Marshal.AllocHGlobal(bufferSize);
335
336 try
337 {
338 //Populate the buffer.
339 if (Win32Interop.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, flags, out regType, buffer, bufferSize, out requiredSize))
340 {
341 return Marshal.PtrToStringAuto(buffer);
342 }
343 else { throw new Win32Exception(Marshal.GetLastWin32Error()); }
344 }
345 catch { throw; }
346 finally
347 {
348 Marshal.FreeHGlobal(buffer);
349 }
350 }
351
352 internal static Dictionary<string, string> GetAllRegistryProperties(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA devInfoData)
353 {
354 var allRegistryProperties = new Dictionary<string, string>();
355 Type type = typeof(DeviceRegistryProperty);
356 var values = (int[])Enum.GetValues(type);
357 string propertyValue;
358
359 foreach (var value in values)
360 {
361 try
362 {
363 propertyValue = GetProperty(deviceInfoSet, ref devInfoData, (uint)value)?.ToString();
364 if (propertyValue == null) propertyValue = string.Empty;
365 }
366 catch
367 { propertyValue = " ~~~~~ Error! ~~~~~ "; } //TODO: Should I provide a different value here?
368
369 allRegistryProperties.Add(
370 Enum.GetName(type, value),
371 propertyValue);
372 }
373
374 return allRegistryProperties;
375 }
376
377 #endregion
378
379 #region Set Properties
380 internal static bool SetProperty(this Device device, int value, DeviceRegistryProperty flags)
381 {
382 if (device.IsDisposed)
383 throw new ObjectDisposedException("Cannot change config flags on the disposed object.", (Exception)null);
384
385 SP_DEVINFO_DATA devInfoData = device.DevInfoData;
386 byte[] buffer = BitConverter.GetBytes(value);
387 unsafe { fixed (byte* bufferPtr = buffer) {
388 IntPtr bufferIntPtr = new IntPtr(bufferPtr);
389 if (Win32Interop.SetupDiSetDeviceRegistryProperty(device.DeviceInfoSet, ref devInfoData, (uint)flags, bufferIntPtr, buffer.Length))
390 {
391 device.DevInfoData = devInfoData;
392 return true;
393 }
394 else throw new Win32Exception(Marshal.GetLastWin32Error());
395 }}
396 }
397
398 internal static bool SetProperty(this Device device, string value, DeviceRegistryProperty flags)
399 {
400 if (device.IsDisposed)
401 throw new ObjectDisposedException("Cannot change property string on the disposed object.", (Exception)null);
402
403 SP_DEVINFO_DATA devInfoData = device.DevInfoData;
404 IntPtr buffer = Marshal.StringToHGlobalAuto(value);
405 int size = value.Length * Marshal.SystemDefaultCharSize;
406
407 if (Win32Interop.SetupDiSetDeviceRegistryProperty(device.DeviceInfoSet, ref devInfoData, (uint)flags, buffer, size))
408 {
409 device.DevInfoData = devInfoData;
410 return true;
411 }
412 else throw new Win32Exception(Marshal.GetLastWin32Error());
413 }
414
415 #region Commented Code
416 //TODO: Why did I delete this method? Does it not work? Does Description cover it well enough?
417 //public void SetFriendlyName(string value)
418 //{
419 // if (this.SetDevicePropertyString(value, DeviceRegistryProperty.FriendlyName))
420 // {
421 // this.FriendlyName = value;
422 // }
423 //}
424 #endregion
425 #endregion
426
427 #region Get device instance id
428
429 internal static string GetDevicePathString(this Device device)
430 {
431 var devInfoData = device.DevInfoData;
432
433 string value = GetDeviceInstancePath(device.DeviceInfoSet, ref devInfoData);
434
435 device.DevInfoData = devInfoData;
436
437 return value;
438 }
439
440 private static string GetDeviceInstancePath(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA devInfoData)
441 {
442 //Allocate the correct amount of memory for the buffer.
443 int bufferSize = 256;
444 int requiredSize = 0;
445 StringBuilder buffer = new StringBuilder(bufferSize);
446 //Populate the buffer.
447 if (Win32Interop.SetupDiGetDeviceInstanceId(deviceInfoSet, ref devInfoData, buffer, bufferSize, out requiredSize))
448 {
449 return buffer.ToString();
450 }
451 else { throw new Win32Exception(Marshal.GetLastWin32Error()); }
452 }
453 #endregion
454
455 #region Get Hardware IDs
456 internal static string[] GetHardwareIDs(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA devInfoData)
457 {
458 IntPtr buffer = IntPtr.Zero;
459 int bufferSize = 0;
460 uint regType = 7, requiredSize = 0;
461
462 uint flags = (uint)DeviceRegistryProperty.HardwareID;
463
464 //Find the correct amount of memory required for the buffer.
465 if (!Win32Interop.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, flags, out regType, buffer, bufferSize, out requiredSize))
466 {
467 int error = Marshal.GetLastWin32Error();
468
469 switch (error)
470 {
471 case Win32Error.InsufficientBuffer:
472 //Do nothing.
473 break;
474 case Win32Error.InvalidData:
475 //Return an empty array.
476 return new string[0];
477 default:
478 //Throw an exception.
479 throw new Win32Exception(error);
480 }
481 }
482
483 //Allocate the correct amount of memory for the buffer.
484 bufferSize = (int)requiredSize;
485 buffer = Marshal.AllocHGlobal(bufferSize);
486
487 try
488 {
489 //Populate the buffer.
490 if (Win32Interop.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, flags, out regType, buffer, bufferSize, out requiredSize))
491 {
492 return PtrToStringArrayAuto(buffer);
493 }
494 else { throw new Win32Exception(Marshal.GetLastWin32Error()); }
495 }
496 catch { throw; }
497 finally
498 {
499 Marshal.FreeHGlobal(buffer);
500 }
501 }
502
503 /// <summary>
504 /// Converts a pointer to an unmanaged string buffer of the
505 /// REG_MULTI_SZ format to an array of strings, excluding
506 /// the null terminating character '\0'.
507 /// </summary>
508 /// <param name="buffer">A pointer to the unmanaged REG_MULTI_SZ buffer.</param>
509 /// <returns>An array containing the strings of the REG_MULTI_SZ value.</returns>
510 private static string[] PtrToStringArrayAuto(IntPtr buffer)
511 {
512 //Notes:
513 // REG_MULTI_SZ is formatted as such: "String1\0String2\0String3\0LastString\0\0"
514
515 int offset = 0;
516 string currentString = string.Empty;
517 List<string> multiStringList = new List<string>();
518
519 while (!string.IsNullOrEmpty(currentString = Marshal.PtrToStringAuto(_IntPtr.Offset(buffer, offset))))
520 {
521 multiStringList.Add(currentString);
522 offset += (currentString.Length + 1) * Marshal.SystemDefaultCharSize; //Note: "+1" for the '\0' terminating character, and "x1" or "x2" for Unicode (two bytes per character).
523 }
524
525 return multiStringList.ToArray();
526 }
527 #endregion
528
529 #region Get Parent of Device
530 internal static int GetDeviceParent(SP_DEVINFO_DATA DeviceInfo)
531 {
532 UInt32 CR_SUCCESS = 0x00000000;
533 int parentDeviceInst = 0;
534 if(Win32Interop.CM_Get_Parent(ref parentDeviceInst, DeviceInfo.DevInst, 0) == CR_SUCCESS)
535 {
536 return parentDeviceInst;
537 }
538 throw new Win32Exception(Marshal.GetLastWin32Error());
539 }
540 #endregion
541 }
542 }
543