Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1975 lines
57 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. ntsetup\hwlog\hwlog.c
  5. Abstract:
  6. Logging some aspects of the hardware configuration to winnt32.log / setupact.log.
  7. Esp. disk drive by connection, and map drive letters to disk drives.
  8. Author:
  9. Jay Krell (JayKrell) April 2001, May 2001
  10. Revision History:
  11. Environment:
  12. winnt32.dll -- Win9x ANSI (down to Win95gold) or NT Unicode
  13. libcmt statically linked in, _tcs* ok
  14. actually only built for Unicode/NT, and does nothing
  15. if run on less than Windows 2000
  16. setup.exe -newsetup -- guimode setup
  17. --*/
  18. /* Platform notes
  19. Win95:
  20. apparently no setupapi.dll (redist)
  21. apparently no cfgmgr32.dll
  22. no kernel32.dll::GetVolumeNameForVolumeMountPoint
  23. NT 3.1
  24. no kernel32.dll::GetVolumeNameForVolumeMountPoint
  25. NT 3.51
  26. apparently no setupapi.dll
  27. apparently no cfgmgr32.dll
  28. no kernel32.dll::GetVolumeNameForVolumeMountPoint
  29. NT4
  30. no kernel32.dll::GetVolumeNameForVolumeMountPoint
  31. setupapi.dll
  32. has SetupDiGetClassDevs
  33. does not have SetupDiGetClassDevsEx
  34. does not have SetupDiEnumDeviceInterfaces
  35. does not have SetupDiGetDeviceInterfaceDetail
  36. cfgmgr32.dll
  37. has the functions we call
  38. Win2000, WinXp:
  39. has all the functions we call
  40. Win98, Win98se:
  41. no kernel32.dll::GetVolumeNameForVolumeMountPoint
  42. setupapi.dll, has everything we use
  43. has SetupDiGetClassDevs
  44. has SetupDiGetClassDevsEx
  45. has SetupDiEnumDeviceInterfaces
  46. has SetupDiGetDeviceInterfaceDetail
  47. cfgmgr32.dll, has everything we use
  48. has CM_Get_Parent_Ex
  49. has CM_Connect_MachineA
  50. has CM_Get_DevNode_Registry_Property_ExA
  51. existing versions of
  52. winnt32a.dll
  53. not statically dependent on setupapi.dll
  54. not statically dependent on cfgmgr32.dll
  55. winnt32u.dll
  56. not statically dependent on setupapi.dll
  57. statically dependent on cfgmgr32.dll, all functions exported on NT4 and Win98
  58. CM_Get_Device_ID_List_SizeW
  59. CM_Get_Device_ID_ListW
  60. CM_Get_DevNode_Registry_PropertyW
  61. CM_Locate_DevNodeW
  62. conclusions
  63. works on Win2000 and WinXp
  64. maybe some of it works on Win98, Win98se, Win9me
  65. maybe can be changed slightly to work on NT4
  66. cannot easily work on NT 3 or Win95
  67. but GetVolumeNameForVolumeMountPoint and the DeviceIoControl might prevent it
  68. dynamically link it "all"
  69. */
  70. #define STANDALONE 0
  71. #define DYNLINK 1
  72. #if STANDALONE
  73. #define UNICODE
  74. #define _UNICODE
  75. #if !defined(_WIN32_WINNT)
  76. #define _WIN32_WINNT 0x0501
  77. #endif
  78. // from windows.h, but we want this before nt.h
  79. #if !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86)
  80. #define _X86_
  81. #endif
  82. #if !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64)
  83. #define _AMD64_
  84. #endif
  85. #if !defined(_IA64_) && !defined(_X86_) && !defined(_M_IX86) && !defined(_AMD64_) && defined(_M_IA64)
  86. #define _IA64_
  87. #endif
  88. #include "io.h"
  89. #if !defined(_WIN64)
  90. typedef unsigned long ULONG_PTR; // vc6 compatibility
  91. typedef unsigned long DWORD_PTR; // vc6 compatibility
  92. #endif
  93. #endif
  94. #include <stdio.h>
  95. #include "nt.h"
  96. #include "ntrtl.h"
  97. #include "nturtl.h"
  98. #include "windows.h"
  99. #include "cfgmgr32.h"
  100. #include "objbase.h"
  101. #include "initguid.h"
  102. #include "devguid.h"
  103. #include "setupapi.h"
  104. #include "winioctl.h"
  105. #include <stdlib.h>
  106. #include "tchar.h"
  107. #include <stdarg.h>
  108. #include <stdlib.h>
  109. #include "hwlog.h"
  110. typedef CONST VOID* PCVOID;
  111. struct _SP_LINKAGE;
  112. typedef struct _SP_LINKAGE SP_LINKAGE, *PSP_LINKAGE;
  113. typedef CONST SP_LINKAGE* PCSP_LINKAGE;
  114. typedef struct _SP_MACHINE {
  115. PCTSTR Name; // for setupapi.dll functions
  116. HMACHINE Handle; // for cfgmgr32.dll functions
  117. } SP_MACHINE, *PSP_MACHINE;
  118. typedef CONST SP_MACHINE* PCSP_MACHINE;
  119. typedef struct _SP_LOG_HARDWARE {
  120. SP_MACHINE Machine;
  121. HANDLE LogFile;
  122. #if !DYNLINK
  123. CONST
  124. #endif
  125. SP_LINKAGE* Linkage;
  126. BOOL (WINAPI* SetupLogError)(PCTSTR MessageString, LogSeverity);
  127. BOOL (__cdecl * SetuplogError)(
  128. IN LogSeverity Severity,
  129. IN LPCTSTR MessageString,
  130. IN UINT MessageId, OPTIONAL
  131. ...
  132. ) OPTIONAL;
  133. } SP_LOG_HARDWARE, *PSP_LOG_HARDWARE;
  134. typedef CONST SP_LOG_HARDWARE* PCSP_LOG_HARDWARE;
  135. #if STANDALONE || defined(UNICODE)
  136. #define QUASH_SIMPLE_PHYSICAL_DEVICE_OBJECT_NAMES 1
  137. #define INDENT_FACTOR 2
  138. #define UNAVAILABLE_VERBOSE 1
  139. #if 0 /* this is more like a small tree, one device per line, indenting */
  140. #define ONE_PROPERTY_PER_LINE 0
  141. #define INDENT_CHILDREN 1
  142. #define NUMBER_CHILDREN 0
  143. #define DESCRIPTION_DASH_PHYSICAL_DEVICE_OBJECT 0
  144. #else
  145. #define ONE_PROPERTY_PER_LINE 1
  146. #define INDENT_CHILDREN 0
  147. #define NUMBER_CHILDREN 1
  148. #define DESCRIPTION_DASH_PHYSICAL_DEVICE_OBJECT 1
  149. #endif
  150. #define ONE_DEVICE_PER_LINE (!ONE_PROPERTY_PER_LINE)
  151. #if !defined(DBG)
  152. #define DBG 1
  153. #endif
  154. #define NUMBER_OF(x) (sizeof(x)/sizeof((x)[0]))
  155. #if !defined(ISNT)
  156. #if STANDALONE || !defined(UNICODE)
  157. #define ISNT() ((GetVersion() & 0x80000000) == 0)
  158. #else
  159. #define ISNT() TRUE
  160. #endif
  161. #endif
  162. #define SP_FILE_SHARE_DELETE() (ISNT() ? FILE_SHARE_DELETE : 0)
  163. // RTL_* from ntdef.h
  164. #define FIELD_TYPE(type, field) (((type*)0)->field)
  165. #define BITS_OF_FIELD(type, field) (BITS_OF(FIELD_TYPE(type, field)))
  166. #define BITS_OF(sizeOfArg) (sizeof(sizeOfArg) * 8)
  167. #define xPASTE(x,y) x##y
  168. #define PASTE(x,y) xPASTE(x,y)
  169. typedef struct _SP_LINKAGE
  170. {
  171. #if DYNLINK
  172. #define U(x) union { PCSTR PASTE(Name, __LINE__); x; }
  173. #else
  174. #define U(x) x
  175. #endif
  176. PCSTR Kernel32Dll;
  177. U(BOOL (WINAPI* GetVolumeNameForVolumeMountPoint)(PCTSTR lpszVolumeMountPoint, PTSTR lpszVolumeName, DWORD cchBufferLength));
  178. PCSTR Setupapidll;
  179. U(BOOL (WINAPI* SetupDiEnumDeviceInterfaces)(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, CONST GUID* InterfaceClassGuid, DWORD MemberIndex, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData));
  180. U(HDEVINFO (WINAPI* SetupDiGetClassDevsEx)(CONST GUID* ClassGuid, PCTSTR Enumerator, HWND hwndParent, DWORD Flags, HDEVINFO DeviceInfoSet, PCTSTR MachineName, PVOID Reserved));
  181. U(BOOL (WINAPI* SetupDiGetDeviceInterfaceDetail)(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData, DWORD DeviceInterfaceDetailDataSize, PDWORD RequiredSize, PSP_DEVINFO_DATA DeviceInfoData));
  182. U(CONFIGRET (WINAPI* CM_Get_Parent_Ex)(OUT PDEVINST pdnDevInst, IN DEVINST dnDevInst, IN ULONG ulFlags, IN HMACHINE hMachine));
  183. U(CONFIGRET (WINAPI* CM_Connect_Machine)(IN PCTSTR UNCServerName, OUT PHMACHINE phMachine));
  184. U(CONFIGRET (WINAPI* CM_Get_DevNode_Registry_Property_Ex)(
  185. IN DEVINST dnDevInst, IN ULONG ulProperty,
  186. OUT PULONG pulRegDataType OPTIONAL, OUT PVOID Buffer OPTIONAL,
  187. IN OUT PULONG pulLength, IN ULONG ulFlags, IN HMACHINE hMachine));
  188. #undef U
  189. } SP_LINKAGE;
  190. #if defined(UNICODE)
  191. #define T "W"
  192. #else
  193. #define T "A"
  194. #endif
  195. #if !DYNLINK
  196. CONST
  197. #endif
  198. static SP_LINKAGE SpLinkage =
  199. {
  200. #if DYNLINK
  201. //
  202. // note: lowercase => .dll name
  203. //
  204. "kernel32.dll",
  205. "GetVolumeNameForVolumeMountPoint" T,
  206. "setupapi.dll",
  207. "SetupDiEnumDeviceInterfaces",
  208. "SetupDiGetClassDevsEx" T,
  209. "SetupDiGetDeviceInterfaceDetail" T,
  210. "CM_Get_Parent_Ex",
  211. "CM_Connect_Machine" T,
  212. "CM_Get_DevNode_Registry_Property_Ex" T
  213. #undef T
  214. #else
  215. NULL, // kernel32
  216. GetVolumeNameForVolumeMountPoint,
  217. NULL, // setupapi
  218. SetupDiEnumDeviceInterfaces,
  219. SetupDiGetClassDevsEx,
  220. SetupDiGetDeviceInterfaceDetail,
  221. CM_Get_Parent_Ex,
  222. CM_Connect_Machine,
  223. CM_Get_DevNode_Registry_Property_Ex
  224. #endif
  225. };
  226. BOOL
  227. SpDoDynlink(
  228. PSP_LOG_HARDWARE This
  229. )
  230. {
  231. #if DYNLINK
  232. SIZE_T i;
  233. FARPROC* rgproc = (FARPROC*)This->Linkage;
  234. PCSTR* rgpsz = (PCSTR*)This->Linkage;
  235. HMODULE DllHandle;
  236. for (i = 0 ; i != sizeof(SpLinkage)/sizeof(PVOID) ; ++i)
  237. {
  238. if (islower(rgpsz[i][0]))
  239. {
  240. if ((DllHandle = LoadLibraryA(rgpsz[i])) == NULL)
  241. return FALSE;
  242. }
  243. else if ((rgproc[i] = GetProcAddress(DllHandle, rgpsz[i])) == NULL)
  244. {
  245. return FALSE;
  246. }
  247. }
  248. #endif
  249. return TRUE;
  250. }
  251. PCTSTR
  252. SpGetSpacesString(
  253. SIZE_T n
  254. );
  255. PCTSTR
  256. SpGetDashesString(
  257. SIZE_T n
  258. );
  259. PVOLUME_DISK_EXTENTS
  260. SpGetVolumeDiskExtents(
  261. HANDLE DeviceFileHandle
  262. );
  263. //
  264. // need a downlevel static .lib version of ntdll.dll..
  265. //
  266. typedef struct SP_STRING {
  267. PTSTR Chars;
  268. SIZE_T Length;
  269. SIZE_T MaximumLength;
  270. } SP_STRING, *PSP_STRING;
  271. typedef CONST SP_STRING* PCSP_STRING;
  272. #define SpStringLength(s) ((s)->Length)
  273. #define SpInitString(s, t) \
  274. ((s)->MaximumLength = sizeof((s)->Chars[0]) + ((s)->Length = lstrlen((s)->Chars = (PTSTR)t)))
  275. VOID
  276. SpHwDebugLog(
  277. PSP_LOG_HARDWARE This,
  278. PCTSTR Format,
  279. ...
  280. );
  281. VOID SpStringAppendFormatVa(PSP_STRING Buffer, PCSP_STRING Format, va_list va)
  282. {
  283. if (Buffer->MaximumLength > Buffer->Length + 1)
  284. {
  285. _vsntprintf(
  286. Buffer->Chars + Buffer->Length,
  287. Buffer->MaximumLength - Buffer->Length,
  288. Format->Chars,
  289. va
  290. );
  291. }
  292. Buffer->Chars[Buffer->MaximumLength - 1] = 0;
  293. }
  294. VOID SpStringAppendFormat(PSP_STRING Buffer, PCSP_STRING Format, ...)
  295. {
  296. va_list va;
  297. va_start(va, Format);
  298. SpStringAppendFormatVa(Buffer, Format, va);
  299. va_end(va);
  300. }
  301. VOID SpStringAppend(PSP_STRING s, PCSP_STRING t)
  302. {
  303. SP_STRING Format;
  304. Format.Chars = TEXT("%s");
  305. Format.Length = 2;
  306. SpStringAppendFormat(s, &Format, t);
  307. }
  308. VOID SpStringCopy(PSP_STRING s, PCSP_STRING t)
  309. {
  310. s->Chars[0] = 0;
  311. SpStringAppend(s, t);
  312. }
  313. VOID SpStringFormat(PSP_STRING s, PCSP_STRING Format, ...)
  314. {
  315. va_list va;
  316. va_start(va, Format);
  317. s->Chars[0] = 0;
  318. SpStringAppendFormatVa(s, Format, va);
  319. va_end(va);
  320. }
  321. PVOID SpMalloc(SIZE_T n)
  322. {
  323. return HeapAlloc(GetProcessHeap(), 0, n);
  324. }
  325. VOID SpFree(PVOID p)
  326. {
  327. HeapFree(GetProcessHeap(), 0, p);
  328. }
  329. PVOID SpRealloc(PVOID p, SIZE_T n)
  330. {
  331. return HeapReAlloc(GetProcessHeap(), 0, p, n);
  332. }
  333. VOID SpStringFree(PTSTR s) { SpFree(s); }
  334. VOID SpRemoveTrailingChars(PSP_STRING s, PCTSTR ch)
  335. {
  336. while (s->Length != 0
  337. && (s->Chars[s->Length - 1] == ch[0] || s->Chars[s->Length - 1] == ch[1])
  338. && !(s->Chars[s->Length - 1] = 0)
  339. && (s->Length -= 1)
  340. )
  341. {
  342. // nothing
  343. }
  344. }
  345. VOID SpEnsureTrailingChar(PSP_STRING s, TCHAR ch)
  346. {
  347. if (s->Length == 0
  348. || s->Chars[s->Length - 1] != ch)
  349. {
  350. s->Length += 1;
  351. s->Chars[s->Length - 1] = ch;
  352. s->Chars[s->Length] = 0;
  353. }
  354. }
  355. //
  356. // for now, let's hope that device numbers stay in the range 0-63
  357. //
  358. typedef struct SP_DEVICE_NUMBERS {
  359. ULONGLONG Bitset;
  360. } SP_DEVICE_NUMBERS, *PSP_DEVICE_NUMBERS;
  361. typedef CONST SP_DEVICE_NUMBERS* PCSP_DEVICE_NUMBERS;
  362. typedef struct SP_VOLUME
  363. {
  364. PTSTR GuidVolumeNamePointer; // if this is null, use GuidVolumeNameBuffer
  365. TCHAR GuidVolumeNameBuffer[64]; // \\?\{guid}
  366. #define SP_VOLUME_GET_NAME(v) (((v)->GuidVolumeNamePointer != NULL) ? (v)->GuidVolumeNamePointer : (v)->GuidVolumeNameBuffer)
  367. //
  368. // DiskNumbers are gotten via DeviceIoControl(STORAGE_DEVICE_NUMBER) (Win2K)
  369. // and DeviceIoControl(IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS) (Whistler)
  370. //
  371. ULONG DeviceType;
  372. SP_DEVICE_NUMBERS DeviceNumbers;
  373. TCHAR DriveLetter;
  374. } SP_VOLUME, *PSP_VOLUME;
  375. typedef CONST SP_VOLUME* PCSP_VOLUME;
  376. //
  377. // most systems are limited to 24 volumes, C-Z, unless they use
  378. // mount points, and setup is unlikely to be affected by those volumes
  379. //
  380. typedef struct _SP_VOLUMES {
  381. SP_VOLUME Entries[24];
  382. } SP_VOLUMES, *PSP_VOLUMES;
  383. typedef CONST SP_VOLUMES* PCSP_VOLUMES;
  384. #define SP_PROPERTY_QUIET_UNAVAILABLE (0x00000001)
  385. typedef struct _SP_DEVICE_PROPERTY_CONST {
  386. //ULONG SetupapiInteger;
  387. ULONG ConfigManagerInteger;
  388. PCTSTR Name;
  389. ULONG Flags;
  390. } SP_DEVICE_PROPERTY_CONST, *PSP_DEVICE_PROPERTY_CONST;
  391. typedef CONST SP_DEVICE_PROPERTY_CONST* PCSP_DEVICE_PROPERTY_CONST;
  392. #if ONE_DEVICE_PER_LINE
  393. //CONST static TCHAR FriendlyNameString[] = TEXT("FriendlyName");
  394. //CONST static TCHAR DescriptionString[] = TEXT("Description");
  395. CONST static TCHAR PhysicalDeviceObjectNameString[] = TEXT("");
  396. CONST static TCHAR HardwareIdString[] = TEXT("");
  397. CONST static TCHAR LowerFiltersString[] = TEXT("");
  398. CONST static TCHAR UpperFiltersString[] = TEXT("");
  399. //CONST static TCHAR FlagsString[] = TEXT("");
  400. CONST static TCHAR LocationInformationString[] = TEXT("");
  401. #else
  402. //CONST static TCHAR FriendlyNameString[] = TEXT("FriendlyName");
  403. //CONST static TCHAR DescriptionString[] = TEXT("Description");
  404. CONST static TCHAR PhysicalDeviceObjectNameString[] = TEXT("PhysicalDeviceObjectName");
  405. CONST static TCHAR HardwareIdString[] = TEXT("HardwareId");
  406. CONST static TCHAR LowerFiltersString[] = TEXT("LowerFilters");
  407. CONST static TCHAR UpperFiltersString[] = TEXT("UpperFilters");
  408. //CONST static TCHAR FlagsString[] = TEXT("Flags");
  409. CONST static TCHAR LocationInformationString[] = TEXT("Location");
  410. #endif
  411. #define SETUPAPI_PROPERTY_NUMBER(x) /* nothing */
  412. #define DESCRIPTION 0
  413. #define PHYSICAL_DEVICE_OBJECT 1
  414. #define FRIENDLY_NAME 2
  415. #define HARDWARE_ID 3
  416. #define FIRST_GENERIC_PROPERTY 4
  417. CONST static SP_DEVICE_PROPERTY_CONST DevicePropertyMetaInfo[] =
  418. {
  419. { SETUPAPI_PROPERTY_NUMBER(SPDRP_DEVICEDESC) CM_DRP_DEVICEDESC, TEXT(""), SP_PROPERTY_QUIET_UNAVAILABLE },
  420. { SETUPAPI_PROPERTY_NUMBER(SPDRP_PHYSICAL_DEVICE_OBJECT_NAME) CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME, PhysicalDeviceObjectNameString },
  421. { SETUPAPI_PROPERTY_NUMBER(SPDRP_FRIENDLYNAME) CM_DRP_FRIENDLYNAME, TEXT(""), SP_PROPERTY_QUIET_UNAVAILABLE },
  422. { SETUPAPI_PROPERTY_NUMBER(SPDRP_HARDWAREID) CM_DRP_HARDWAREID, HardwareIdString },
  423. { SETUPAPI_PROPERTY_NUMBER(x) CM_DRP_LOCATION_INFORMATION, LocationInformationString, SP_PROPERTY_QUIET_UNAVAILABLE },
  424. { SETUPAPI_PROPERTY_NUMBER(SPDRP_LOWERFILTERS) CM_DRP_LOWERFILTERS, LowerFiltersString, SP_PROPERTY_QUIET_UNAVAILABLE },
  425. { SETUPAPI_PROPERTY_NUMBER(SPDRP_UPPERFILTERS) CM_DRP_UPPERFILTERS, UpperFiltersString, SP_PROPERTY_QUIET_UNAVAILABLE },
  426. //{ SETUPAPI_PROPERTY_NUMBER(x) CM_DRP_CONFIGFLAGS, FlagsString },
  427. //{ SETUPAPI_PROPERTY_NUMBER(x) CM_DRP_CAPABILITIES, TEXT("Capabilities") },
  428. //{ SETUPAPI_PROPERTY_NUMBER(x) CM_DRP_UI_NUMBER, TEXT("UI Number") },
  429. //{ SETUPAPI_PROPERTY_NUMBER(x) CM_DRP_CHARACTERISTICS, TEXT("Characteristics") },
  430. //{ SETUPAPI_PROPERTY_NUMBER(x) CM_DRP_ADDRESS, TEXT("Address") },
  431. };
  432. typedef struct _SP_DEVICE_PROPERTY {
  433. PCSP_DEVICE_PROPERTY_CONST Const;
  434. TCHAR Value[256];
  435. ULONG Type;
  436. } SP_DEVICE_PROPERTY, *PSP_DEVICE_PROPERTY;
  437. typedef CONST SP_DEVICE_PROPERTY* PCSP_DEVICE_PROPERTY;
  438. typedef struct _SP_DEVICE_CLASS {
  439. CONST GUID* Guid;
  440. ULONG IsInterface;
  441. //PCTSTR Name;
  442. } SP_DEVICE_CLASS, *PSP_DEVICE_CLASS;
  443. typedef CONST SP_DEVICE_CLASS* PCSP_DEVICE_CLASS;
  444. /*
  445. CONST static TCHAR VolumesString[] = TEXT("Volumes");
  446. CONST static TCHAR DisksString[] = TEXT("Disks");
  447. CONST static TCHAR CDROMsString[] = TEXT("CDROMs");
  448. CONST static TCHAR PartitionsString[] = TEXT("Partitions");
  449. */
  450. CONST static SP_DEVICE_CLASS DeviceClasses[] =
  451. {
  452. { &GUID_DEVINTERFACE_CDROM, DIGCF_DEVICEINTERFACE, /*CDROMsString*/ },
  453. { &GUID_DEVINTERFACE_DISK, DIGCF_DEVICEINTERFACE, /*DisksString*/ },
  454. { &GUID_DEVINTERFACE_PARTITION, DIGCF_DEVICEINTERFACE, /*PartitionsString*/ },
  455. // The information this adds is not very useful.
  456. //{ &GUID_DEVINTERFACE_VOLUME, DIGCF_DEVICEINTERFACE, /*VolumesString*/ },
  457. };
  458. typedef struct _SP_DEVICE {
  459. PCSP_DEVICE_CLASS Class;
  460. ULONG DevInst;
  461. ULONG DeviceType;
  462. SP_DEVICE_NUMBERS DeviceNumbers;
  463. //BOOL IsLeaf;
  464. SIZE_T NumberOfParents;
  465. ULONG ParentDevInsts[MAX_DEVICE_ID_LEN];
  466. TCHAR DevicePath[MAX_PATH];
  467. TCHAR GuidVolumePath[64];
  468. //SP_DEVICE_PROPERTY Properties[NUMBER_OF(DevicePropertyMetaInfo)];
  469. } SP_DEVICE, *PSP_DEVICE;
  470. typedef CONST SP_DEVICE* PCSP_DEVICE;
  471. #define SP_IS_PATH_SEPERATOR(ch) ((ch) == '\\' || (ch) == '/')
  472. SIZE_T
  473. SpStringLengthWithoutTrailingPathSeperators(
  474. PCTSTR s
  475. )
  476. {
  477. SIZE_T Length;
  478. if (s == NULL || *s == 0)
  479. return 0;
  480. Length = _tcslen(s);
  481. s += Length - 1;
  482. while (SP_IS_PATH_SEPERATOR(s[Length]))
  483. Length -= 1;
  484. return Length;
  485. }
  486. int __cdecl SpCompareVolume(CONST VOID* v1, CONST VOID* v2)
  487. {
  488. CONST PCSP_VOLUME p1 = (PCSP_VOLUME)v1;
  489. CONST PCSP_VOLUME p2 = (PCSP_VOLUME)v2;
  490. CONST PCTSTR s1 = (p1 != NULL) ? SP_VOLUME_GET_NAME(p1) : TEXT("");
  491. CONST SIZE_T len1 = SpStringLengthWithoutTrailingPathSeperators(s1);
  492. CONST PCTSTR s2 = (p1 != NULL) ? SP_VOLUME_GET_NAME(p2) : TEXT("");
  493. CONST SIZE_T len2 = SpStringLengthWithoutTrailingPathSeperators(s2);
  494. return _tcsicmp(s1, s2);
  495. }
  496. VOID SpSortVolumes(PSP_VOLUMES Volumes)
  497. {
  498. qsort(
  499. Volumes->Entries,
  500. NUMBER_OF(Volumes->Entries),
  501. sizeof(Volumes->Entries[0]),
  502. SpCompareVolume
  503. );
  504. }
  505. PCSP_VOLUME
  506. SpFindVolume(
  507. PSP_VOLUMES Volumes,
  508. PCTSTR VolumeGuidPath
  509. )
  510. {
  511. CONST SP_VOLUME VolumeKey = { (PTSTR)VolumeGuidPath };
  512. PCSP_VOLUME VolumeFound =
  513. (PCSP_VOLUME)
  514. bsearch(
  515. &VolumeKey,
  516. Volumes->Entries,
  517. NUMBER_OF(Volumes->Entries),
  518. sizeof(Volumes->Entries[0]),
  519. SpCompareVolume
  520. );
  521. return VolumeFound;
  522. }
  523. #if 0
  524. void
  525. SpCovertRNToN(
  526. PTSTR Buffer
  527. )
  528. {
  529. PTSTR p;
  530. PTSTR q;
  531. for (p = q = Buffer ; *p != 0 && *(p + 1) != 0 ; )
  532. {
  533. if (*p == '\r' && *(p + 1) == '\n')
  534. {
  535. *q++ = '\n';
  536. p += 2;
  537. }
  538. else
  539. {
  540. *q++ = *p++;
  541. }
  542. }
  543. if (*p != 0)
  544. *q++ = *p++;
  545. *q++ = 0;
  546. }
  547. void
  548. SpCovertNToRN(
  549. PTSTR Buffer
  550. )
  551. {
  552. // determine size
  553. // heap alloc
  554. // convert
  555. }
  556. #endif
  557. VOID
  558. SpHwDebugLog(
  559. PSP_LOG_HARDWARE This,
  560. PCTSTR Format,
  561. ...
  562. )
  563. {
  564. va_list va;
  565. TCHAR BufferT[500];
  566. #ifdef UNICODE
  567. CHAR BufferA[500];
  568. #endif
  569. SIZE_T Length;
  570. BOOLEAN Newline = FALSE;
  571. BufferT[0] = 0;
  572. va_start(va, Format);
  573. FormatMessage(
  574. FORMAT_MESSAGE_FROM_STRING,
  575. Format,
  576. 0,
  577. 0,
  578. BufferT,
  579. NUMBER_OF(BufferT),
  580. &va
  581. );
  582. BufferT[NUMBER_OF(BufferT) - 1] = 0;
  583. Length = lstrlen(BufferT);
  584. if (Length != 0)
  585. {
  586. #if 0
  587. Newline = (BufferT[Length - 1] == '\n' || BufferT[Length - 1] == '\r');
  588. if (Newline)
  589. {
  590. while (Length != 0 && (BufferT[Length - 1] == '\n' || BufferT[Length - 1] == '\r'))
  591. Length -= 1;
  592. if (Length != 0)
  593. BufferT[Length] = 0;
  594. else
  595. Newline = FALSE;
  596. }
  597. #endif
  598. if (Newline)
  599. lstrcat(BufferT, TEXT("\r\n"));
  600. if (This->LogFile != NULL)
  601. {
  602. DWORD BytesWritten;
  603. if (Newline)
  604. lstrcat(BufferT, TEXT("\r\n"));
  605. #ifdef UNICODE
  606. WideCharToMultiByte(
  607. CP_ACP,
  608. 0,
  609. BufferT,
  610. -1,
  611. BufferA,
  612. sizeof(BufferA) - 1,
  613. NULL,
  614. NULL
  615. );
  616. WriteFile(This->LogFile, &BufferA, lstrlenA(BufferA), &BytesWritten, NULL);
  617. #else
  618. WriteFile(This->LogFile, &BufferT, lstrlen(BufferT), &BytesWritten, NULL);
  619. #endif
  620. }
  621. if (This->SetupLogError != NULL)
  622. {
  623. This->SetupLogError(BufferT, LogSevInformation);
  624. }
  625. if (This->SetuplogError != NULL)
  626. {
  627. This->SetuplogError(
  628. LogSevInformation,
  629. TEXT("%1"),
  630. 0,
  631. BufferT,
  632. (PVOID)NULL,
  633. (PVOID)NULL
  634. );
  635. }
  636. }
  637. va_end(va);
  638. }
  639. #define SpHwLog SpHwDebugLog
  640. #if 0
  641. VOID PrependString(PTSTR s, PCTSTR t)
  642. {
  643. SIZE_T slen = _tcslen(s);
  644. SIZE_T tlen = _tcslen(t);
  645. MoveMemory(s + tlen, s, (slen + 1) * sizeof(*s));
  646. MoveMemory(s, t, tlen);
  647. }
  648. #endif
  649. #define SP_CLOSE_HANDLE(h) \
  650. do { if ((h) != NULL && (h) != INVALID_HANDLE_VALUE) { CloseHandle(h); h = INVALID_HANDLE_VALUE; } } while(0)
  651. #define SP_FREE(p) \
  652. do { if ((p) != NULL) { SpFree(p); (p) = NULL; } } while(0)
  653. PVOLUME_DISK_EXTENTS
  654. SpGetVolumeDiskExtents(
  655. HANDLE DeviceFileHandle
  656. )
  657. /*++
  658. Routine Description:
  659. Arguments:
  660. Return Value:
  661. --*/
  662. {
  663. //
  664. // This pattern is iffy, but it is used elsewhere, and the implementation of
  665. // IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS is iffy too, and not quite as documented.
  666. // See drivers\vsm\vsmio\nt\voldev.c.
  667. //
  668. struct {
  669. VOLUME_DISK_EXTENTS VolumeDiskExtents;
  670. DISK_EXTENT DiskExtents[4];
  671. } StackDiskExtents;
  672. PVOLUME_DISK_EXTENTS HeapDiskExtents = NULL;
  673. PVOLUME_DISK_EXTENTS DiskExtents = NULL;
  674. PVOLUME_DISK_EXTENTS ResultDiskExtents = NULL;
  675. DWORD BytesReturned;
  676. BOOL Success = FALSE;
  677. DWORD Size;
  678. DiskExtents = &StackDiskExtents.VolumeDiskExtents;
  679. Size = sizeof(StackDiskExtents);
  680. //
  681. // loop in case it is changing
  682. //
  683. while (!Success)
  684. {
  685. Success =
  686. DeviceIoControl(
  687. DeviceFileHandle,
  688. IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
  689. NULL,
  690. 0,
  691. DiskExtents,
  692. Size,
  693. &BytesReturned,
  694. NULL
  695. );
  696. if (!Success) {
  697. if (GetLastError() != ERROR_MORE_DATA)
  698. goto Exit;
  699. Size = sizeof(VOLUME_DISK_EXTENTS) + DiskExtents->NumberOfDiskExtents * sizeof(DISK_EXTENT);
  700. SP_FREE(HeapDiskExtents);
  701. HeapDiskExtents = (PVOLUME_DISK_EXTENTS)SpMalloc(Size);
  702. if (HeapDiskExtents == NULL) {
  703. SetLastError(ERROR_OUTOFMEMORY);
  704. goto Exit;
  705. }
  706. DiskExtents = HeapDiskExtents;
  707. } else {
  708. if (DiskExtents->NumberOfDiskExtents == 0) {
  709. /* nothing */
  710. }
  711. else if (DiskExtents == HeapDiskExtents) {
  712. ResultDiskExtents = HeapDiskExtents;
  713. HeapDiskExtents = NULL;
  714. } else if (DiskExtents == &StackDiskExtents.VolumeDiskExtents) {
  715. // VOLUME_DISK_EXTENTS includes an array of one DISK_EXTENT at the end.
  716. ASSERT(BytesReturned == (sizeof(VOLUME_DISK_EXTENTS) + (DiskExtents->NumberOfDiskExtents - 1) * sizeof(DISK_EXTENT)));
  717. ResultDiskExtents = (PVOLUME_DISK_EXTENTS)SpMalloc(BytesReturned);
  718. if (ResultDiskExtents == NULL) {
  719. SetLastError(ERROR_OUTOFMEMORY);
  720. goto Exit;
  721. }
  722. ASSERT(BytesReturned <= sizeof(StackDiskExtents));
  723. CopyMemory(ResultDiskExtents, &StackDiskExtents, BytesReturned);
  724. } else {
  725. ASSERT(FALSE && "DiskExtents != HeapDiskExtents, StackDiskExtents");
  726. }
  727. }
  728. }
  729. Exit:
  730. SP_FREE(HeapDiskExtents);
  731. return ResultDiskExtents;
  732. }
  733. PTSTR
  734. SpDeviceTypeToString(
  735. ULONG i,
  736. PTSTR s
  737. )
  738. {
  739. //
  740. // this is a partial list from public\ddk\inc\devioctl.h
  741. //
  742. PCTSTR t = NULL;
  743. s[0] = 0;
  744. switch (i)
  745. {
  746. case FILE_DEVICE_CD_ROM: t = TEXT("CDROM"); break;
  747. case FILE_DEVICE_CD_ROM_FILE_SYSTEM: t = TEXT("CDROM File System"); break;
  748. case FILE_DEVICE_CONTROLLER: t = TEXT("Device Controller"); break;
  749. case FILE_DEVICE_DFS: t = TEXT("Distributed File System"); break;
  750. case FILE_DEVICE_DISK: t = TEXT("Disk"); break;
  751. case FILE_DEVICE_DISK_FILE_SYSTEM: t = TEXT("Disk File System"); break;
  752. case FILE_DEVICE_FILE_SYSTEM: t = TEXT("File System"); break;
  753. case FILE_DEVICE_NETWORK_FILE_SYSTEM: t = TEXT("Network File System"); break;
  754. case FILE_DEVICE_TAPE: t = TEXT("Tape"); break;
  755. case FILE_DEVICE_TAPE_FILE_SYSTEM: t = TEXT("Tape File System"); break;
  756. case FILE_DEVICE_VIRTUAL_DISK: t = TEXT("Virtual Disk"); break;
  757. case FILE_DEVICE_NETWORK_REDIRECTOR: t = TEXT("Network Redirector"); break;
  758. case FILE_DEVICE_MASS_STORAGE: t = TEXT("Mass Storage"); break;
  759. case FILE_DEVICE_SMB: t = TEXT("SMB"); break;
  760. case FILE_DEVICE_CHANGER: t = TEXT("Changer"); break;
  761. case FILE_DEVICE_ACPI: t = TEXT("ACPI"); break;
  762. case FILE_DEVICE_DFS_FILE_SYSTEM: t = TEXT("DFS File System"); break;
  763. case FILE_DEVICE_DFS_VOLUME: t = TEXT("DFS Volume"); break;
  764. default:
  765. _stprintf(s, TEXT("Other (%ld)"), i);
  766. break;
  767. }
  768. if (t != NULL)
  769. _tcscpy(s, t);
  770. return s;
  771. }
  772. VOID
  773. SpGetDeviceNumbersAndType(
  774. PSP_LOG_HARDWARE This,
  775. PCTSTR DevicePath,
  776. PSP_DEVICE_NUMBERS DeviceNumbers,
  777. PULONG DeviceType
  778. )
  779. {
  780. PVOLUME_DISK_EXTENTS VolumeDiskExtents = NULL;
  781. STORAGE_DEVICE_NUMBER StorageDeviceNumber = { 0 };
  782. DWORD Error = 0;
  783. DWORD DeviceIoControlBytesReturned = 0;
  784. CONST static TCHAR Function[] = TEXT("SpGetDeviceNumbersAndType");
  785. HANDLE DeviceFileHandle = INVALID_HANDLE_VALUE;
  786. #if 0
  787. SpHwDebugLog(
  788. This,
  789. TEXT("%1: DeviceIoControl(%2)\n"),
  790. Function,
  791. DevicePath
  792. );
  793. #endif
  794. DeviceFileHandle =
  795. CreateFile(
  796. DevicePath,
  797. GENERIC_READ,
  798. FILE_SHARE_READ | FILE_SHARE_READ | SP_FILE_SHARE_DELETE(),
  799. NULL,
  800. OPEN_EXISTING,
  801. FILE_ATTRIBUTE_NORMAL,
  802. NULL
  803. );
  804. if (DeviceFileHandle == INVALID_HANDLE_VALUE
  805. ) {
  806. Error = GetLastError();
  807. if (Error != ERROR_FILE_NOT_FOUND) {
  808. SpHwDebugLog(
  809. This,
  810. TEXT("%1: CreateFile(%2) warning %3!lu!\r\n"),
  811. Function,
  812. DevicePath,
  813. Error
  814. );
  815. }
  816. goto Exit;
  817. }
  818. if (!DeviceIoControl(
  819. DeviceFileHandle,
  820. IOCTL_STORAGE_GET_DEVICE_NUMBER,
  821. NULL,
  822. 0,
  823. &StorageDeviceNumber,
  824. sizeof(StorageDeviceNumber),
  825. &DeviceIoControlBytesReturned,
  826. NULL
  827. )) {
  828. Error = GetLastError();
  829. if (Error != ERROR_INVALID_FUNCTION
  830. && Error != ERROR_FILE_NOT_FOUND
  831. && Error != ERROR_INVALID_PARAMETER // dynamic disk
  832. )
  833. {
  834. SpHwDebugLog(
  835. This,
  836. TEXT("%1: DeviceIoControl(%2) warning %3!lu!\r\n"),
  837. Function,
  838. DevicePath,
  839. Error
  840. );
  841. }
  842. if (Error == ERROR_INVALID_PARAMETER)
  843. {
  844. // dynamic disk
  845. *DeviceType = FILE_DEVICE_DISK;
  846. }
  847. } else if (DeviceIoControlBytesReturned < sizeof(StorageDeviceNumber)) {
  848. SpHwDebugLog(
  849. This,
  850. TEXT("%1: DeviceIoControl size mismatch (%4!lu!, %5!lu!)"),
  851. Function,
  852. (ULONG)DeviceIoControlBytesReturned,
  853. (ULONG)sizeof(StorageDeviceNumber)
  854. );
  855. } else {
  856. CONST ULONG DeviceNumber = StorageDeviceNumber.DeviceNumber;
  857. #if 0
  858. {
  859. TCHAR DeviceTypeString[64];
  860. SpHwDebugLog(
  861. This,
  862. TEXT("%1: DeviceType of %2 is %3 (%4!lu!)\r\n"),
  863. Function,
  864. DevicePath,
  865. SpDeviceTypeToString(StorageDeviceNumber.DeviceType, DeviceTypeString),
  866. StorageDeviceNumber.DeviceType
  867. );
  868. }
  869. #endif
  870. *DeviceType = StorageDeviceNumber.DeviceType;
  871. if (DeviceNumber > 63) {
  872. SpHwDebugLog(
  873. This,
  874. TEXT("%1: DeviceNumber out of range (%2!lu!)\r\n"),
  875. Function,
  876. StorageDeviceNumber.DeviceNumber
  877. );
  878. }
  879. else {
  880. #if 0
  881. SpHwDebugLog(
  882. This,
  883. TEXT("%1 disk number %2!lu!\r\n"),
  884. DevicePath,
  885. DeviceNumber
  886. );
  887. #endif
  888. DeviceNumbers->Bitset |= (1ui64 << DeviceNumber);
  889. }
  890. }
  891. VolumeDiskExtents = (PVOLUME_DISK_EXTENTS) SpGetVolumeDiskExtents(DeviceFileHandle);
  892. if (VolumeDiskExtents != NULL) {
  893. SIZE_T i;
  894. CONST SIZE_T VolumeDiskExtents_NumberOfDiskExtents = VolumeDiskExtents->NumberOfDiskExtents;
  895. for (i = 0 ; i != VolumeDiskExtents_NumberOfDiskExtents ; ++i) {
  896. CONST SIZE_T DiskNumber = VolumeDiskExtents->Extents[i].DiskNumber;
  897. if (DiskNumber > 63) {
  898. SpHwDebugLog(
  899. This,
  900. TEXT("%1: DiskNumber out of range (%2!lu!)\r\n"),
  901. Function,
  902. DiskNumber
  903. );
  904. }
  905. else {
  906. DeviceNumbers->Bitset |= (1ui64 << DiskNumber);
  907. }
  908. }
  909. }
  910. Exit:
  911. SP_CLOSE_HANDLE(DeviceFileHandle);
  912. SpFree(VolumeDiskExtents);
  913. }
  914. VOID
  915. SpCollectVolumeInformation(
  916. PSP_LOG_HARDWARE This,
  917. PSP_VOLUMES Volumes
  918. )
  919. /*++
  920. Routine Description:
  921. Arguments:
  922. Return Value:
  923. --*/
  924. {
  925. TCHAR DriveLetter;
  926. TCHAR GuidVolumeNameBuffer[NUMBER_OF(Volumes->Entries[0].GuidVolumeNameBuffer)];
  927. CONST static TCHAR Function[] = TEXT("SpCollectVolumeInformation");
  928. DWORD Error;
  929. SP_STRING GuidVolumeNameString;
  930. ZeroMemory(Volumes, sizeof(*Volumes));
  931. for (DriveLetter = 'C' ; DriveLetter <= 'Z' ; DriveLetter++) {
  932. CONST PSP_VOLUME Volume = &Volumes->Entries[DriveLetter - 'C'];
  933. CONST TCHAR DriveLetterPath[] = { DriveLetter, ':', '\\', 0 };
  934. CONST TCHAR DeviceDriveLetterPath[] = { '\\', '\\', '.', '\\', DriveLetter, ':', 0 };
  935. /* This looks interesting. WindowsXp only.
  936. if (GetVolumePathNamesForVolumeName(DriveLetterPath, VolumeName, NUMBER_OF(VolumeName)))
  937. {
  938. }
  939. */
  940. GuidVolumeNameBuffer[0] = 0;
  941. if (!This->Linkage->GetVolumeNameForVolumeMountPoint(
  942. DriveLetterPath, GuidVolumeNameBuffer, NUMBER_OF(GuidVolumeNameBuffer) - 1)
  943. )
  944. {
  945. Error = GetLastError();
  946. if (Error != ERROR_FILE_NOT_FOUND
  947. && Error != ERROR_PATH_NOT_FOUND
  948. ) {
  949. SpHwDebugLog(
  950. This,
  951. TEXT("%1: GetVolumeNameForVolumeMountPoint(%2) warning %3!lu!\r\n"),
  952. Function,
  953. DriveLetterPath,
  954. Error
  955. );
  956. }
  957. continue;
  958. }
  959. SpInitString(&GuidVolumeNameString, GuidVolumeNameBuffer);
  960. SpRemoveTrailingChars(&GuidVolumeNameString, TEXT("\\/"));
  961. Volume->DriveLetter = DriveLetter;
  962. CopyMemory(&Volume->GuidVolumeNameBuffer, &GuidVolumeNameBuffer, sizeof(GuidVolumeNameBuffer));
  963. SpGetDeviceNumbersAndType(
  964. This,
  965. Volume->GuidVolumeNameBuffer,
  966. &Volume->DeviceNumbers,
  967. &Volume->DeviceType
  968. );
  969. }
  970. qsort(Volumes->Entries, NUMBER_OF(Volumes->Entries), sizeof(Volumes->Entries[0]), SpCompareVolume);
  971. //Exit:
  972. ;
  973. }
  974. BOOLEAN
  975. SpCollectDeviceProperties(
  976. PSP_LOG_HARDWARE This,
  977. ULONG DevInst,
  978. SIZE_T NumberOfProperties,
  979. PCSP_DEVICE_PROPERTY_CONST InArray,
  980. PSP_DEVICE_PROPERTY OutArray
  981. )
  982. {
  983. BOOLEAN Success = FALSE;
  984. SIZE_T PropertyIndex = 0;
  985. CONFIGRET ConfigRet = 0;
  986. CONST static TCHAR Function[] = TEXT("SpCollectDeviceProperties");
  987. SP_STRING ValueString;
  988. SP_STRING Whitespace;
  989. SpInitString(&Whitespace, TEXT("\r\n\v\t "));
  990. for (PropertyIndex = 0 ; PropertyIndex != NumberOfProperties ; PropertyIndex += 1)
  991. {
  992. PCSP_DEVICE_PROPERTY_CONST In = &InArray[PropertyIndex];
  993. PSP_DEVICE_PROPERTY Out = &OutArray[PropertyIndex];
  994. ULONG PropertyBufferSize = sizeof(Out->Value);
  995. //
  996. // zero out two chars due to multi_sz
  997. //
  998. Out->Value[0] = 0;
  999. Out->Value[1] = 0;
  1000. ConfigRet =
  1001. This->Linkage->CM_Get_DevNode_Registry_Property_Ex(
  1002. DevInst,
  1003. In->ConfigManagerInteger,
  1004. &Out->Type,
  1005. Out->Value,
  1006. &PropertyBufferSize,
  1007. 0,
  1008. This->Machine.Handle
  1009. );
  1010. if (ConfigRet == CR_BUFFER_SMALL)
  1011. {
  1012. //
  1013. // zero out two chars due to multi_sz
  1014. //
  1015. Out->Value[0] = 0;
  1016. Out->Value[1] = 0;
  1017. #if DBG
  1018. SpHwDebugLog(
  1019. This,
  1020. TEXT("%1: Buffer too small, property %2\r\n"),
  1021. Function,
  1022. DevicePropertyMetaInfo[PropertyIndex].Name
  1023. );
  1024. #endif
  1025. }
  1026. #if UNAVAILABLE_VERBOSE
  1027. if (ConfigRet == CR_NO_SUCH_VALUE
  1028. && (DevicePropertyMetaInfo[PropertyIndex].Flags & SP_PROPERTY_QUIET_UNAVAILABLE) == 0
  1029. )
  1030. {
  1031. _tcscpy(Out->Value, TEXT("<unavailable>"));
  1032. ConfigRet = CR_SUCCESS;
  1033. }
  1034. #endif
  1035. if (Out->Type == REG_SZ)
  1036. {
  1037. SpInitString(&ValueString, Out->Value);
  1038. SpRemoveTrailingChars(&ValueString, TEXT("\r\n"));
  1039. }
  1040. #if QUASH_SIMPLE_PHYSICAL_DEVICE_OBJECT_NAMES
  1041. /* of the form \Device\12345678 */
  1042. if (ConfigRet == CR_SUCCESS
  1043. && In->ConfigManagerInteger == CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME
  1044. )
  1045. {
  1046. CONST static TCHAR SimpleDeviceName[] = TEXT("\\Device\\12345678");
  1047. if (lstrlen(Out->Value) == NUMBER_OF(SimpleDeviceName) - 1)
  1048. {
  1049. SIZE_T i;
  1050. for (i = 0 ; i != NUMBER_OF(SimpleDeviceName) - 1 ; ++i)
  1051. {
  1052. if (iswdigit(SimpleDeviceName[i]) && iswdigit(Out->Value[i]))
  1053. {
  1054. // ok
  1055. }
  1056. else if (SimpleDeviceName[i] != Out->Value[i])
  1057. {
  1058. break;
  1059. }
  1060. }
  1061. if (i == NUMBER_OF(SimpleDeviceName) - 1)
  1062. {
  1063. Out->Value[0] = 0;
  1064. Out->Value[1] = 0;
  1065. }
  1066. }
  1067. }
  1068. #endif
  1069. if (ConfigRet != CR_SUCCESS
  1070. && ConfigRet != CR_NO_SUCH_VALUE
  1071. && ConfigRet != CR_INVALID_PROPERTY
  1072. && ConfigRet != CR_BUFFER_SMALL
  1073. )
  1074. goto Exit;
  1075. Out->Const = In; // connect it back to the meta info
  1076. }
  1077. Success = TRUE;
  1078. Exit:;
  1079. return Success;
  1080. }
  1081. BOOL
  1082. SpGrowArray(
  1083. IN OUT PVOID* Array,
  1084. IN SIZE_T SizeOfElement,
  1085. IN OUT PSIZE_T NumberOfElements,
  1086. IN OUT PSIZE_T NumberAllocated
  1087. )
  1088. {
  1089. ASSERT(*NumberOfElements < *NumberAllocated);
  1090. *NumberOfElements += 1;
  1091. if (*NumberOfElements >= *NumberAllocated) {
  1092. PVOID Next = SpRealloc(*Array, SizeOfElement * *NumberAllocated * 2);
  1093. if (Next == NULL) {
  1094. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1095. return FALSE;
  1096. }
  1097. *Array = Next;
  1098. *NumberAllocated *= 2;
  1099. }
  1100. return TRUE;
  1101. }
  1102. VOID
  1103. SpCollectDeviceInformation(
  1104. PSP_LOG_HARDWARE This,
  1105. PCSP_DEVICE_CLASS DeviceClasses,
  1106. SIZE_T NumberOfDeviceClasses,
  1107. PCSP_DEVICE_PROPERTY_CONST DevicePropertyMetaInfo, // the size of this is assumed
  1108. PSP_DEVICE* OutDevices,
  1109. SIZE_T* OutNumberOfDevices
  1110. )
  1111. /*++
  1112. Routine Description:
  1113. Arguments:
  1114. Return Value:
  1115. --*/
  1116. {
  1117. CONST static TCHAR Function[] = TEXT("SpCollectDeviceInformation");
  1118. SIZE_T DeviceClassIndex = 0;
  1119. ULONG DeviceInClassIndex = 0;
  1120. SIZE_T NumberOfDevices = 0;
  1121. SIZE_T NumberOfDevicesAllocated = 64;
  1122. HANDLE DeviceInfoHandle = NULL;
  1123. BOOL Success = FALSE;
  1124. SP_DEVICE_INTERFACE_DATA SetupDeviceInterfaceData = { sizeof(SetupDeviceInterfaceData) };
  1125. DWORD Error = 0;
  1126. PSP_DEVICE Devices = NULL;
  1127. ULONG DevInst = 0;
  1128. ULONG ParentIndex = 0;
  1129. SP_STRING String;
  1130. struct
  1131. {
  1132. SP_DEVICE_INTERFACE_DETAIL_DATA Base;
  1133. TCHAR Buffer[MAX_PATH];
  1134. } DetailAndBuffer;
  1135. SP_DEVINFO_DATA SetupDeviceInfoData = { sizeof(SetupDeviceInfoData) };
  1136. CONFIGRET ConfigRet = 0;
  1137. if (OutDevices != NULL)
  1138. *OutDevices = NULL;
  1139. if (OutNumberOfDevices != NULL)
  1140. *OutNumberOfDevices = 0;
  1141. if (OutDevices == NULL || OutNumberOfDevices == NULL)
  1142. goto Exit;
  1143. DetailAndBuffer.Base.cbSize = sizeof(DetailAndBuffer.Base);
  1144. Devices = (PSP_DEVICE)SpMalloc(NumberOfDevicesAllocated * sizeof(*Devices));
  1145. if (Devices == NULL)
  1146. goto Exit;
  1147. ZeroMemory(Devices, NumberOfDevicesAllocated * sizeof(*Devices));
  1148. //
  1149. // loop over device class (disk, volume, cdrom, etc.)
  1150. //
  1151. for (DeviceClassIndex = 0 ; DeviceClassIndex != NumberOfDeviceClasses ; ++DeviceClassIndex) {
  1152. DeviceInfoHandle =
  1153. This->Linkage->SetupDiGetClassDevsEx(
  1154. DeviceClasses[DeviceClassIndex].Guid,
  1155. NULL,
  1156. NULL,
  1157. DIGCF_PRESENT | DeviceClasses[DeviceClassIndex].IsInterface,
  1158. NULL,
  1159. This->Machine.Name,
  1160. NULL
  1161. );
  1162. if (DeviceInfoHandle == INVALID_HANDLE_VALUE)
  1163. {
  1164. Error = GetLastError();
  1165. continue;
  1166. }
  1167. //
  1168. // loop over devices in the class
  1169. //
  1170. Success = TRUE;
  1171. for (DeviceInClassIndex = 0 ; Success ; ++DeviceInClassIndex) {
  1172. PSP_DEVICE Device = &Devices[NumberOfDevices];
  1173. Success =
  1174. This->Linkage->SetupDiEnumDeviceInterfaces(
  1175. DeviceInfoHandle,
  1176. NULL,//&SetupDeviceInfoData,
  1177. DeviceClasses[DeviceClassIndex].Guid,
  1178. DeviceInClassIndex,
  1179. &SetupDeviceInterfaceData
  1180. );
  1181. if (!Success)
  1182. Error = GetLastError();
  1183. if (!Success && Error == ERROR_NO_MORE_ITEMS) {
  1184. break;
  1185. }
  1186. if (!Success) {
  1187. break;
  1188. }
  1189. //
  1190. // get the devinst and the device path
  1191. //
  1192. DevInst = SetupDeviceInfoData.DevInst;
  1193. Success =
  1194. This->Linkage->SetupDiGetDeviceInterfaceDetail(
  1195. DeviceInfoHandle,
  1196. &SetupDeviceInterfaceData,
  1197. &DetailAndBuffer.Base,
  1198. sizeof(DetailAndBuffer),
  1199. NULL, /* required size */
  1200. &SetupDeviceInfoData
  1201. );
  1202. if (!Success) {
  1203. break;
  1204. }
  1205. //Device->IsLeaf = TRUE;
  1206. Device->DevInst = SetupDeviceInfoData.DevInst;
  1207. _tcscpy(Device->DevicePath, DetailAndBuffer.Base.DevicePath);
  1208. #if 0
  1209. SpHwDebugLog(
  1210. This,
  1211. TEXT("%1: %2\r\n"),
  1212. Function,
  1213. Device->DevicePath
  1214. );
  1215. #endif
  1216. #if 1
  1217. SpInitString(&String, Device->DevicePath);
  1218. SpEnsureTrailingChar(&String, '\\');
  1219. if (!This->Linkage->GetVolumeNameForVolumeMountPoint(Device->DevicePath,
  1220. Device->GuidVolumePath, NUMBER_OF(Device->GuidVolumePath) - 1)
  1221. ) {
  1222. Error = GetLastError();
  1223. if (Error != ERROR_FILE_NOT_FOUND
  1224. && Error != ERROR_PATH_NOT_FOUND
  1225. && Error != ERROR_NOT_READY
  1226. && Error != ERROR_INVALID_FUNCTION
  1227. )
  1228. {
  1229. SpHwDebugLog(
  1230. This,
  1231. TEXT("%1: GetVolumeNameForVolumeMountPoint(%2) warning %3!lu!\r\n"),
  1232. Function,
  1233. Device->DevicePath,
  1234. Error
  1235. );
  1236. continue;
  1237. }
  1238. }
  1239. //SpHwDebugLog(This, TEXT("%1: GetVolumeNameForVolumeMountPoint(%2) : %3\r\n"), Function, Device->DevicePath, Device->GuidVolumePath);
  1240. SpRemoveTrailingChars(&String, TEXT("\\/"));
  1241. SpInitString(&String, Device->GuidVolumePath);
  1242. SpRemoveTrailingChars(&String, TEXT("\\/"));
  1243. #endif
  1244. //
  1245. // this is how we match up the devices to the drive letters
  1246. //
  1247. SpGetDeviceNumbersAndType(
  1248. This,
  1249. Device->DevicePath,
  1250. &Device->DeviceNumbers,
  1251. &Device->DeviceType
  1252. );
  1253. //
  1254. // get the parent devinsts
  1255. //
  1256. for (
  1257. (ConfigRet = CR_SUCCESS), (ParentIndex = 0);
  1258. (ConfigRet == CR_SUCCESS)
  1259. && ParentIndex < NUMBER_OF(Device->ParentDevInsts);
  1260. ParentIndex += 1
  1261. )
  1262. {
  1263. ULONG ChildIndex = (ParentIndex == 0 ? Device->DevInst : Device->ParentDevInsts[ParentIndex - 1]);
  1264. ConfigRet =
  1265. This->Linkage->CM_Get_Parent_Ex(
  1266. &Device->ParentDevInsts[ParentIndex],
  1267. ChildIndex,
  1268. 0,
  1269. This->Machine.Handle
  1270. );
  1271. }
  1272. // the last one is never interesting, err.. two
  1273. if (ParentIndex != 0)
  1274. ParentIndex -= 1;
  1275. if (ParentIndex != 0)
  1276. ParentIndex -= 1;
  1277. Device->NumberOfParents = ParentIndex;
  1278. //
  1279. // get the properties
  1280. // we should do this here, but not if we don't also get the parent properties
  1281. //
  1282. //SpCollectDeviceProperties(Device, DevicePropertyMetaInfo);
  1283. //
  1284. // grow the array of devices if necessary
  1285. //
  1286. if (!SpGrowArray(&Devices, sizeof(Devices[0]), &NumberOfDevices, &NumberOfDevicesAllocated))
  1287. goto Exit;
  1288. //
  1289. // We should probably the properties of the parents here,
  1290. // but our data structures are not very good, and this would be inefficient
  1291. // We must avoid O(n^2) behavior, because people really do have machines
  1292. // with many disks, like 100.
  1293. //
  1294. // We should keep sorted arrays of devinsts.
  1295. //
  1296. }
  1297. }
  1298. if (!Success) {
  1299. Error = GetLastError();
  1300. }
  1301. //SpChangeParentDevInstsToIndices(Devices, NumberOfDevices);
  1302. *OutDevices = Devices;
  1303. Devices = NULL;
  1304. *OutNumberOfDevices = NumberOfDevices;
  1305. Exit:
  1306. SpFree(Devices);
  1307. }
  1308. VOID
  1309. SpFillStaticString(
  1310. PTSTR s,
  1311. SIZE_T n,
  1312. TCHAR ch
  1313. )
  1314. /*++
  1315. Routine Description:
  1316. Arguments:
  1317. Return Value:
  1318. --*/
  1319. {
  1320. ULONGLONG chch;
  1321. ULONGLONG* pchch;
  1322. SIZE_T i;
  1323. SIZE_T m;
  1324. if (s[n - 2] != 0)
  1325. return;
  1326. if (sizeof(ULONGLONG) <= sizeof(TCHAR))
  1327. {
  1328. for (i = 0 ; i != n - 1 ; i += 1)
  1329. {
  1330. s[i] = ch;
  1331. }
  1332. return;
  1333. }
  1334. chch = 0;
  1335. for (i = 0 ; i != sizeof(ULONGLONG)/sizeof(TCHAR) ; i += 1)
  1336. {
  1337. chch <<= BITS_OF(ch);
  1338. chch |= ch;
  1339. }
  1340. m = (n - 1) / (sizeof(ULONGLONG)/sizeof(TCHAR));
  1341. pchch = (ULONGLONG*)s;
  1342. for (i = 0 ; i < m ; i += 1)
  1343. {
  1344. pchch[i] = chch;
  1345. }
  1346. m *= (sizeof(ULONGLONG)/sizeof(TCHAR));
  1347. for (i = m ; i < n - 1 ; i += 1)
  1348. {
  1349. s[i] = ch;
  1350. }
  1351. #if DBG
  1352. for (i = 0 ; i != n - 1 ; i += 1)
  1353. {
  1354. ASSERT(s[i] == ch);
  1355. }
  1356. ASSERT(s[i] == 0);
  1357. #endif
  1358. }
  1359. PCTSTR
  1360. SpGetDashesString(
  1361. SIZE_T n
  1362. )
  1363. /*++
  1364. Routine Description:
  1365. Arguments:
  1366. Return Value:
  1367. --*/
  1368. {
  1369. static union {
  1370. ULONGLONG Ulonglongs[1 + 128 / (sizeof(ULONGLONG)/sizeof(TCHAR))];
  1371. TCHAR Tchars[128];
  1372. } u;
  1373. SpFillStaticString(u.Tchars, NUMBER_OF(u.Tchars), '-');
  1374. n *= 2;
  1375. if (n > NUMBER_OF(u.Tchars))
  1376. n = NUMBER_OF(u.Tchars);
  1377. return &u.Tchars[NUMBER_OF(u.Tchars) - n];
  1378. }
  1379. PCTSTR
  1380. SpGetSpacesString(
  1381. SIZE_T n
  1382. )
  1383. /*++
  1384. Routine Description:
  1385. Arguments:
  1386. Return Value:
  1387. --*/
  1388. {
  1389. static union {
  1390. ULONGLONG Ulonglongs[1 + 128 / (sizeof(ULONGLONG)/sizeof(TCHAR))];
  1391. TCHAR Tchars[128];
  1392. } u;
  1393. SpFillStaticString(u.Tchars, NUMBER_OF(u.Tchars), ' ');
  1394. n *= INDENT_FACTOR;
  1395. if (n > NUMBER_OF(u.Tchars))
  1396. n = NUMBER_OF(u.Tchars);
  1397. return &u.Tchars[NUMBER_OF(u.Tchars) - 1 - n];
  1398. }
  1399. PCTSTR
  1400. SpGetFirstMultipleString(
  1401. PCTSTR s
  1402. )
  1403. {
  1404. //
  1405. // the first string being empty is odd case
  1406. // it is the only string that can be empty
  1407. //
  1408. if (*s == 0 && *(s + 1) != 0)
  1409. s += 1;
  1410. return s;
  1411. }
  1412. PCTSTR
  1413. SpGetNextMultipleString(
  1414. PCTSTR s
  1415. )
  1416. {
  1417. s += lstrlen(s) + 1;
  1418. return s;
  1419. }
  1420. SIZE_T
  1421. SpMultipleStringCount(
  1422. PCTSTR s
  1423. )
  1424. {
  1425. SIZE_T i = 0;
  1426. if (*s != 0 || *(s + 1) != 0)
  1427. {
  1428. do
  1429. {
  1430. i += 1;
  1431. s += lstrlen(s) + 1;
  1432. } while (*s != 0);
  1433. }
  1434. return i;
  1435. }
  1436. VOID
  1437. SpLogDeviceProperties(
  1438. PSP_LOG_HARDWARE This,
  1439. SIZE_T NumberOfProperties,
  1440. PCSP_DEVICE_PROPERTY PropertyData,
  1441. ULONG Indent
  1442. )
  1443. {
  1444. ULONG PropertyType;
  1445. SIZE_T PropertyIndex;
  1446. //
  1447. // we save away this string, so we that can indent the rest of the lines to account for it
  1448. //
  1449. TCHAR NumberString[BITS_OF(Indent)];
  1450. NumberString[0] = 0;
  1451. #if NUMBER_CHILDREN
  1452. _stprintf(NumberString, TEXT("%lu. "), Indent + 1);
  1453. #endif
  1454. #if ONE_DEVICE_PER_LINE
  1455. SpHwLog(This, TEXT("%1"), SpGetSpacesString(Indent));
  1456. #endif
  1457. for (PropertyIndex = 0 ; PropertyIndex != NumberOfProperties ; PropertyIndex += 1)
  1458. {
  1459. PCTSTR Name = PropertyData[PropertyIndex].Const->Name;
  1460. if (PropertyData[PropertyIndex].Value[0] != 0
  1461. && (PropertyIndex == 0
  1462. //
  1463. // friendly name sometimes == description
  1464. // general fix: don't print adjacent equal values,
  1465. // unless they are both unavailable (which don't generally have anymore)
  1466. //
  1467. || _tcsicmp(PropertyData[PropertyIndex].Value, PropertyData[PropertyIndex - 1].Value) != 0
  1468. || _tcsicmp(PropertyData[PropertyIndex].Value, TEXT("<unavailable>")) == 0
  1469. ))
  1470. {
  1471. #if DESCRIPTION_DASH_PHYSICAL_DEVICE_OBJECT
  1472. if (PropertyIndex == PHYSICAL_DEVICE_OBJECT)
  1473. {
  1474. // nothing
  1475. }
  1476. else
  1477. #endif
  1478. {
  1479. #if NUMBER_CHILDREN
  1480. SpHwLog(This, TEXT("%1"), NumberString);
  1481. #endif
  1482. #if INDENT_CHILDREN && !ONE_DEVICE_PER_LINE
  1483. SpHwLog(This, TEXT("%1"), SpGetSpacesString(Indent));
  1484. #endif
  1485. }
  1486. //
  1487. // only print "PhysicalDeviceObject" if there was no description
  1488. //
  1489. #if DESCRIPTION_DASH_PHYSICAL_DEVICE_OBJECT
  1490. if (PropertyIndex == PHYSICAL_DEVICE_OBJECT
  1491. && (
  1492. PropertyData[DESCRIPTION].Value[0] != 0
  1493. && _tcsicmp(PropertyData[DESCRIPTION].Value, TEXT("<unavailable>")) != 0)
  1494. )
  1495. {
  1496. // nothing
  1497. }
  1498. else
  1499. #endif
  1500. {
  1501. if (Name != NULL && Name[0] != 0)
  1502. {
  1503. //SpHwLog(This, TEXT("%1 = "), Name);
  1504. SpHwLog(This, TEXT("%1: "), Name);
  1505. }
  1506. }
  1507. PropertyType = PropertyData[PropertyIndex].Type;
  1508. // if one device per line, shrink hardware id to just first item
  1509. // also compress its formating if it only contains one element
  1510. #if ONE_PROPERTY_PER_LINE
  1511. if (PropertyType == REG_MULTI_SZ
  1512. && SpMultipleStringCount(PropertyData[PropertyIndex].Value) < 2
  1513. )
  1514. #endif
  1515. {
  1516. PropertyType = REG_SZ;
  1517. }
  1518. switch (PropertyType)
  1519. {
  1520. case REG_MULTI_SZ:
  1521. {
  1522. PCTSTR Value;
  1523. for (
  1524. Value = SpGetFirstMultipleString(PropertyData[PropertyIndex].Value);
  1525. *Value != 0;
  1526. Value = SpGetNextMultipleString(Value)
  1527. )
  1528. {
  1529. #if INDENT_CHILDREN
  1530. SpHwLog(
  1531. This,
  1532. TEXT("\r\n%1%2"),
  1533. SpGetSpacesString(Indent + 2),
  1534. Value
  1535. );
  1536. #else
  1537. SpHwLog(
  1538. This,
  1539. TEXT("\r\n%1 %2"),
  1540. NumberString,
  1541. Value
  1542. );
  1543. #endif
  1544. }
  1545. }
  1546. case REG_SZ:
  1547. SpHwLog(This, TEXT("%1"), PropertyData[PropertyIndex].Value);
  1548. break;
  1549. }
  1550. #if DESCRIPTION_DASH_PHYSICAL_DEVICE_OBJECT
  1551. if (PropertyIndex == DESCRIPTION
  1552. && PropertyData[PHYSICAL_DEVICE_OBJECT].Value[0] != 0
  1553. )
  1554. {
  1555. SpHwLog(This, TEXT(" - "));
  1556. }
  1557. else
  1558. #endif
  1559. {
  1560. #if ONE_PROPERTY_PER_LINE
  1561. SpHwLog(This, TEXT("\r\n"));
  1562. #endif
  1563. #if ONE_DEVICE_PER_LINE
  1564. SpHwLog(This, TEXT(" "));
  1565. #endif
  1566. }
  1567. if (NumberString[0] != 0 && NumberString[0] != ' ')
  1568. {
  1569. //
  1570. // convert to spaces for the rest of the lines
  1571. //
  1572. SIZE_T i;
  1573. for (i = 0 ; NumberString[i] != 0 ; ++i)
  1574. {
  1575. NumberString[i] = ' ';
  1576. }
  1577. }
  1578. }
  1579. }
  1580. #if ONE_DEVICE_PER_LINE
  1581. SpHwLog(This, TEXT("\r\n"));
  1582. #endif
  1583. }
  1584. VOID
  1585. SpLogDeviceTree(
  1586. PSP_LOG_HARDWARE This,
  1587. PCSP_DEVICE Device,
  1588. ULONG Indent
  1589. )
  1590. {
  1591. ULONG ParentIndex;
  1592. SP_DEVICE_PROPERTY PropertyData[NUMBER_OF(DevicePropertyMetaInfo)];
  1593. if (!SpCollectDeviceProperties(This, Device->DevInst, NUMBER_OF(PropertyData), DevicePropertyMetaInfo, PropertyData))
  1594. return;
  1595. #if NUMBER_CHILDREN
  1596. Indent = 1;
  1597. #endif
  1598. SpLogDeviceProperties(This, NUMBER_OF(PropertyData), PropertyData, Indent - 1);
  1599. for (ParentIndex = 0 ; ParentIndex < Device->NumberOfParents ; ParentIndex += 1)
  1600. {
  1601. if (!SpCollectDeviceProperties(This, Device->ParentDevInsts[ParentIndex], NUMBER_OF(PropertyData), DevicePropertyMetaInfo, PropertyData))
  1602. break;
  1603. SpLogDeviceProperties(This, NUMBER_OF(PropertyData), PropertyData, Indent + ParentIndex);
  1604. }
  1605. #if NUMBER_CHILDREN
  1606. SpHwLog(This, TEXT("\r\n"));
  1607. #endif
  1608. }
  1609. VOID
  1610. SpLogVolumeAndDeviceInformation(
  1611. PSP_LOG_HARDWARE This,
  1612. PCSP_VOLUMES Volumes,
  1613. PCSP_DEVICE Devices,
  1614. SIZE_T NumberOfDevices
  1615. )
  1616. {
  1617. ULONG Indent = 0;
  1618. SIZE_T VolumeIndex = 0;
  1619. SIZE_T DiskNumber = 0;
  1620. SIZE_T DeviceIndex = 0;
  1621. for (DeviceIndex = 0; DeviceIndex != NumberOfDevices ; DeviceIndex += 1)
  1622. {
  1623. PCSP_DEVICE Device = &Devices[DeviceIndex];
  1624. for (DiskNumber = 0 ; DiskNumber != BITS_OF_FIELD(SP_DEVICE_NUMBERS, Bitset); DiskNumber += 1)
  1625. {
  1626. if ((Device->DeviceNumbers.Bitset & (1ui64 << DiskNumber)) != 0)
  1627. {
  1628. ULONG DriveLetters = 0;
  1629. LONG NumberOfDriveLetters = 0;
  1630. for (VolumeIndex = 0 ; VolumeIndex != NUMBER_OF(Volumes->Entries) ; ++VolumeIndex)
  1631. {
  1632. CONST PCSP_VOLUME Volume = &Volumes->Entries[VolumeIndex];
  1633. if (Volume->DriveLetter != 0
  1634. && (Volume->DeviceNumbers.Bitset & (1ui64 << DiskNumber)) != 0
  1635. && Volume->DeviceType == Device->DeviceType
  1636. )
  1637. {
  1638. DriveLetters |= (1UL << (Volume->DriveLetter - 'C'));
  1639. NumberOfDriveLetters += 1;
  1640. }
  1641. }
  1642. if (DriveLetters != 0)
  1643. {
  1644. SIZE_T i;
  1645. SpHwLog(
  1646. This,
  1647. TEXT("%1"),
  1648. SpGetSpacesString(Indent)
  1649. );
  1650. SpHwLog(
  1651. This,
  1652. TEXT("%1: "),
  1653. (NumberOfDriveLetters == 1)
  1654. ? TEXT("Volume")
  1655. : TEXT("Volumes")
  1656. );
  1657. for (i = 'C' ; i <= 'Z' ; i += 1)
  1658. {
  1659. if ((DriveLetters & (1UL << (i - 'C'))) != 0)
  1660. SpHwLog(
  1661. This,
  1662. TEXT("%1!c!:\\ "),
  1663. i
  1664. );
  1665. }
  1666. SpHwLog(This, TEXT("%1"), TEXT("\r\n\r\n"));
  1667. }
  1668. #if 1
  1669. SpHwLog(
  1670. This,
  1671. TEXT("Device Path: %1%2"),
  1672. Device->DevicePath,
  1673. TEXT("\r\n\r\n")
  1674. );
  1675. #endif
  1676. //SpHwLog(This, TEXT("\r\n"));
  1677. SpLogDeviceTree(This, Device, Indent + 1);
  1678. //SpHwLog(This, TEXT("\r\n\r\n"));
  1679. SpHwLog(
  1680. This,
  1681. TEXT("%1\r\n\r\n"),
  1682. SpGetDashesString(100)
  1683. );
  1684. }
  1685. }
  1686. }
  1687. }
  1688. VOID
  1689. SpLogHardware(
  1690. PSP_LOG_HARDWARE_IN In
  1691. )
  1692. {
  1693. SP_VOLUMES Volumes = { 0 };
  1694. PSP_DEVICE Devices = NULL;
  1695. SIZE_T NumberOfDevices = 0;
  1696. CONFIGRET ConfigRet = 0;
  1697. SP_MACHINE Machine = { 0 };
  1698. SP_LOG_HARDWARE This = { 0 };
  1699. This.Machine.Name = In->MachineName;
  1700. This.LogFile = In->LogFile;
  1701. This.Linkage = &SpLinkage;
  1702. This.SetupLogError = In->SetupLogError;
  1703. This.SetuplogError = In->SetuplogError;
  1704. if (!SpDoDynlink(&This))
  1705. {
  1706. SpHwLog(&This, TEXT("downlevel, deviceinfo not logged\r\n"));
  1707. return;
  1708. }
  1709. ConfigRet = This.Linkage->CM_Connect_Machine(This.Machine.Name, &This.Machine.Handle);
  1710. if (ConfigRet != CR_SUCCESS)
  1711. goto Exit;
  1712. SpCollectVolumeInformation(
  1713. &This,
  1714. &Volumes
  1715. );
  1716. SpCollectDeviceInformation(
  1717. &This,
  1718. DeviceClasses,
  1719. NUMBER_OF(DeviceClasses),
  1720. DevicePropertyMetaInfo,
  1721. &Devices,
  1722. &NumberOfDevices
  1723. );
  1724. if (Devices != NULL && NumberOfDevices != 0)
  1725. {
  1726. SpLogVolumeAndDeviceInformation(
  1727. &This,
  1728. &Volumes,
  1729. Devices,
  1730. NumberOfDevices
  1731. );
  1732. SpFree(Devices);
  1733. }
  1734. Exit:
  1735. ;
  1736. }
  1737. #if STANDALONE
  1738. void Main(
  1739. PSP_LOG_HARDWARE_IN Parameters
  1740. )
  1741. {
  1742. #if STANDALONE == 1
  1743. Parameters->LogFile = (HANDLE)_get_osfhandle(_fileno(stdout));
  1744. #elif STANDALONE == 2
  1745. SetupOpenLog(FALSE);
  1746. Parameters->SetupLogError = SetupLogError;
  1747. #endif
  1748. SpLogHardware(Parameters);
  1749. #if STANDALONE == 2
  1750. SetupCloseLog();
  1751. #endif
  1752. }
  1753. #ifdef UNICODE
  1754. int __cdecl _wmain(int argc, WCHAR** argv)
  1755. {
  1756. SP_LOG_HARDWARE_IN Parameters = { 0 };
  1757. Parameters.MachineName = (argc > 1) ? argv[1] : NULL;
  1758. Main(&Parameters);
  1759. return 0;
  1760. }
  1761. #endif
  1762. int __cdecl main(int argc, CHAR** argv)
  1763. {
  1764. SP_LOG_HARDWARE_IN Parameters = { 0 };
  1765. #ifdef UNICODE
  1766. WCHAR** argvw = NULL;
  1767. argvw = CommandLineToArgvW(GetCommandLineW(), &argc);
  1768. Parameters.MachineName = (argc > 1) ? argvw[1] : NULL;
  1769. #else
  1770. Parameters.MachineName = (argc > 1) ? argv[1] : NULL;
  1771. #endif
  1772. Main(&Parameters);
  1773. return 0;
  1774. }
  1775. #endif
  1776. #else
  1777. VOID
  1778. SpLogHardware(
  1779. PSP_LOG_HARDWARE_IN In
  1780. )
  1781. {
  1782. }
  1783. #endif