Source code of Windows XP (NT5)
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.

572 lines
17 KiB

  1. #include <objbase.h>
  2. #include <stdio.h>
  3. #include <shpriv.h>
  4. #pragma warning(disable: 4201)
  5. #include <winioctl.h>
  6. #pragma warning(disable: 4200)
  7. #include <ntddcdvd.h>
  8. #include <ntddmmc.h>
  9. #include <ntddcdrm.h>
  10. #include "mischlpr.h"
  11. #include "sfstr.h"
  12. #include "unk.h"
  13. #include "fact.h"
  14. // {DD522ACC-F821-461a-A407-50B198B896DC}
  15. /*extern const CLSID CLSID_HardwareDevices =
  16. {0xdd522acc, 0xf821, 0x461a,
  17. {0xa4, 0x7, 0x50, 0xb1, 0x98, 0xb8, 0x96, 0xdc}};
  18. extern const IID IID_IHardwareDevices =
  19. {0x77CDD897, 0xF595, 0x4897,
  20. {0xA9, 0x14, 0x6E, 0x91, 0x77, 0x1C, 0xC3, 0x30}};*/
  21. #define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0]))
  22. struct CDDEVINFO
  23. {
  24. BOOL fMMC2; // icon, label, say for sure what type
  25. DWORD dwDriveType;
  26. DWORD dwMediaType;
  27. BOOL fHasMedia;
  28. BOOL fMediaFormatted;
  29. BOOL fHasAudioTracks;
  30. BOOL fHasData;
  31. BOOL fHasAutorunINF;
  32. BOOL fHasDesktopINI;
  33. BOOL fHasDVDMovie; // autorun.inf takes precedence
  34. WCHAR szFileSystem[100];
  35. WCHAR szVolGUID[50];
  36. WCHAR szVolDeviceID[200];
  37. };
  38. static CDDEVINFO cddevinfo[100] = {0};
  39. static DWORD ccddevinfo = 0;
  40. struct _sFLAG_DESCR
  41. {
  42. DWORD dwFlag;
  43. LPTSTR pszDescr;
  44. LPTSTR pszComment;
  45. };
  46. #define FLAG_DESCR(a) { (DWORD)a, TEXT(#a), NULL }
  47. int _PrintFlag(DWORD dwFlag, _sFLAG_DESCR rgflag[], DWORD cflag,
  48. DWORD /*cchIndent*/, BOOL fPrintValue, BOOL fHex, BOOL fComment, BOOL fORed)
  49. {
  50. int i = 0;
  51. BOOL fAtLeastOne = FALSE;
  52. for (DWORD dw = 0; dw < cflag; ++dw)
  53. {
  54. BOOL fPrint = FALSE;
  55. if (fORed)
  56. {
  57. if (rgflag[dw].dwFlag & dwFlag)
  58. {
  59. fPrint = TRUE;
  60. }
  61. }
  62. else
  63. {
  64. if (rgflag[dw].dwFlag == dwFlag)
  65. {
  66. fPrint = TRUE;
  67. }
  68. }
  69. if (fPrint)
  70. {
  71. if (fAtLeastOne)
  72. {
  73. i += wprintf(TEXT("\n"));
  74. }
  75. if (fPrintValue)
  76. {
  77. if (fHex)
  78. {
  79. i += wprintf(TEXT("0x%08X, "), rgflag[dw].dwFlag);
  80. }
  81. else
  82. {
  83. i += wprintf(TEXT("%u, "), rgflag[dw].dwFlag);
  84. }
  85. }
  86. i += wprintf(TEXT("%s"), rgflag[dw].pszDescr);
  87. if (fComment)
  88. {
  89. i += wprintf(TEXT(", '%s'"), rgflag[dw].pszComment);
  90. }
  91. fAtLeastOne = TRUE;
  92. }
  93. }
  94. return i;
  95. }
  96. _sFLAG_DESCR _featurenumberFD[] =
  97. {
  98. FLAG_DESCR(FeatureProfileList),
  99. FLAG_DESCR(FeatureCore),
  100. FLAG_DESCR(FeatureMorphing),
  101. FLAG_DESCR(FeatureRemovableMedium),
  102. FLAG_DESCR(FeatureRandomReadable),
  103. FLAG_DESCR(FeatureMultiRead),
  104. FLAG_DESCR(FeatureCdRead),
  105. FLAG_DESCR(FeatureDvdRead),
  106. FLAG_DESCR(FeatureRandomWritable),
  107. FLAG_DESCR(FeatureIncrementalStreamingWritable),
  108. FLAG_DESCR(FeatureSectorErasable),
  109. FLAG_DESCR(FeatureFormattable),
  110. FLAG_DESCR(FeatureDefectManagement),
  111. FLAG_DESCR(FeatureWriteOnce),
  112. FLAG_DESCR(FeatureRestrictedOverwrite),
  113. FLAG_DESCR(FeatureWriteProtect),
  114. FLAG_DESCR(FeatureCdrwCAVWrite),
  115. FLAG_DESCR(FeatureRigidRestrictedOverwrite),
  116. FLAG_DESCR(FeatureCdTrackAtOnce),
  117. FLAG_DESCR(FeatureCdMastering),
  118. FLAG_DESCR(FeatureDvdRecordableWrite),
  119. FLAG_DESCR(FeaturePowerManagement),
  120. FLAG_DESCR(FeatureSMART),
  121. FLAG_DESCR(FeatureEmbeddedChanger),
  122. FLAG_DESCR(FeatureCDAudioAnalogPlay),
  123. FLAG_DESCR(FeatureMicrocodeUpgrade),
  124. FLAG_DESCR(FeatureTimeout),
  125. FLAG_DESCR(FeatureDvdCSS),
  126. FLAG_DESCR(FeatureRealTimeStreaming),
  127. FLAG_DESCR(FeatureLogicalUnitSerialNumber),
  128. FLAG_DESCR(FeatureDiscControlBlocks),
  129. FLAG_DESCR(FeatureDvdCPRM),
  130. };
  131. HRESULT ProcessMMC2Features(CDDEVINFO* pcddevinfo)
  132. {
  133. HANDLE hDevice = CreateFile(pcddevinfo->szVolDeviceID, GENERIC_READ,
  134. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  135. if (INVALID_HANDLE_VALUE != hDevice)
  136. {
  137. DWORD cbReturned;
  138. GET_CONFIGURATION_IOCTL_INPUT input;
  139. DWORD cbHeader = sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER);
  140. GET_CONFIGURATION_HEADER* pheader = (GET_CONFIGURATION_HEADER*)LocalAlloc(LPTR,
  141. cbHeader);
  142. if (pheader)
  143. {
  144. FEATURE_HEADER* pfh;
  145. input.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE;
  146. input.Reserved[0] = NULL;
  147. input.Reserved[1] = NULL;
  148. for (DWORD dw = 0; dw < ARRAYSIZE(_featurenumberFD); ++dw)
  149. {
  150. input.Feature = (FEATURE_NUMBER)(_featurenumberFD[dw].dwFlag);
  151. BOOL f = DeviceIoControl(hDevice,
  152. IOCTL_CDROM_GET_CONFIGURATION,
  153. &input,
  154. sizeof(GET_CONFIGURATION_IOCTL_INPUT),
  155. pheader,
  156. cbHeader,
  157. &cbReturned,
  158. NULL);
  159. pfh = (FEATURE_HEADER*)(pheader->Data);
  160. if (f)
  161. {
  162. WORD w = (pfh->FeatureCode[0]) << 8 | (pfh->FeatureCode[1]);
  163. if (w == (WORD)(_featurenumberFD[dw].dwFlag))
  164. {
  165. wprintf(TEXT(" "));
  166. if (pfh->Current)
  167. {
  168. wprintf(TEXT("* "));
  169. }
  170. else
  171. {
  172. wprintf(TEXT(" "));
  173. }
  174. _PrintFlag(_featurenumberFD[dw].dwFlag, _featurenumberFD, ARRAYSIZE(_featurenumberFD),
  175. 0, FALSE, FALSE, FALSE, FALSE);
  176. wprintf(TEXT("\n"));
  177. }
  178. }
  179. }
  180. }
  181. CloseHandle(hDevice);
  182. }
  183. return S_OK;
  184. }
  185. HRESULT ProcessCDInfo(LPCWSTR pszMountPoint, CDDEVINFO* pcddevinfo, BOOL fMMC2Features)
  186. {
  187. wprintf(TEXT("\n--------------------------------------------------------\n"));
  188. wprintf(TEXT(" %s\n\n"), pszMountPoint);
  189. if (pcddevinfo->fMMC2)
  190. {
  191. wprintf(TEXT(" (1) Drive is MMC2 compliant. It should have an icon and label\n"));
  192. wprintf(TEXT(" that reflects its capabilites in My Computer when it\n"));
  193. wprintf(TEXT(" contains no media.\n"));
  194. wprintf(TEXT(" (1.1) Drive capabilities are:\n"));
  195. if (pcddevinfo->dwDriveType & HWDDC_CDROM)
  196. {
  197. wprintf(TEXT(" CD-ROM\n"));
  198. }
  199. if (pcddevinfo->dwDriveType & HWDDC_CDRECORDABLE)
  200. {
  201. wprintf(TEXT(" CD-R\n"));
  202. }
  203. if (pcddevinfo->dwDriveType & HWDDC_CDREWRITABLE)
  204. {
  205. wprintf(TEXT(" CD-RW\n"));
  206. }
  207. if (pcddevinfo->dwDriveType & HWDDC_DVDROM)
  208. {
  209. wprintf(TEXT(" DVD-ROM\n"));
  210. }
  211. if (pcddevinfo->dwDriveType & HWDDC_DVDRECORDABLE)
  212. {
  213. wprintf(TEXT(" DVD-R\n"));
  214. }
  215. if (pcddevinfo->dwDriveType & HWDDC_DVDREWRITABLE)
  216. {
  217. wprintf(TEXT(" DVD-RW\n"));
  218. }
  219. if (pcddevinfo->dwDriveType & HWDDC_DVDRAM)
  220. {
  221. wprintf(TEXT(" DVD-RAM\n"));
  222. }
  223. }
  224. else
  225. {
  226. wprintf(TEXT(" (1) Drive is *NOT* MMC2 compliant. It cannot have an icon and label\n"));
  227. wprintf(TEXT(" that reflects its capabilites in My Computer when it contains no media.\n"));
  228. wprintf(TEXT(" It only has a CD icon and label. We cannot say for sure what are its\n"));
  229. wprintf(TEXT(" capabilities either (CD-RW, DVD, ...). MMC2 compliance is required\n"));
  230. wprintf(TEXT(" for the Windows Logo.\n"));
  231. }
  232. if (pcddevinfo->fHasMedia)
  233. {
  234. wprintf(TEXT(" (2) Drive contains a media.\n"));
  235. if (pcddevinfo->fMMC2)
  236. {
  237. wprintf(TEXT(" (2.1) Media capabilities are:\n"));
  238. if (pcddevinfo->dwMediaType & HWDMC_CDROM)
  239. {
  240. wprintf(TEXT(" CD-ROM\n"));
  241. }
  242. if (pcddevinfo->dwMediaType & HWDMC_CDRECORDABLE)
  243. {
  244. wprintf(TEXT(" CD-R\n"));
  245. }
  246. if (pcddevinfo->dwMediaType & HWDMC_CDREWRITABLE)
  247. {
  248. wprintf(TEXT(" CD-RW\n"));
  249. }
  250. if (pcddevinfo->dwMediaType & HWDMC_DVDROM)
  251. {
  252. wprintf(TEXT(" DVD-ROM\n"));
  253. }
  254. if (pcddevinfo->dwMediaType & HWDMC_DVDRECORDABLE)
  255. {
  256. wprintf(TEXT(" DVD-R\n"));
  257. }
  258. if (pcddevinfo->dwMediaType & HWDMC_DVDREWRITABLE)
  259. {
  260. wprintf(TEXT(" DVD-RW\n"));
  261. }
  262. if (pcddevinfo->dwMediaType & HWDMC_DVDRAM)
  263. {
  264. wprintf(TEXT(" DVD-RAM\n"));
  265. }
  266. }
  267. if (pcddevinfo->fMediaFormatted)
  268. {
  269. wprintf(TEXT(" (3) The media is formatted (non-blank).\n"));
  270. wprintf(TEXT(" (3.1) The file-system is: '%s'.\n"), pcddevinfo->szFileSystem);
  271. }
  272. else
  273. {
  274. wprintf(TEXT(" (3) The media is *NOT* formatted (blank).\n"));
  275. }
  276. }
  277. else
  278. {
  279. wprintf(TEXT(" (2) Drive does *NOT* contain media.\n"));
  280. }
  281. if (pcddevinfo->fHasAudioTracks)
  282. {
  283. wprintf(TEXT(" (4) The media has Audio Tracks (not same as MP3s).\n"));
  284. if (pcddevinfo->fHasAutorunINF)
  285. {
  286. wprintf(TEXT(" (4.1) But it also contains an Autorun.inf which\n"));
  287. wprintf(TEXT(" should take precedence when Autoplay'ing.\n"));
  288. }
  289. }
  290. if (pcddevinfo->fHasData)
  291. {
  292. wprintf(TEXT(" (5) The media contains data files/executables.\n"));
  293. }
  294. if (pcddevinfo->fHasAutorunINF)
  295. {
  296. wprintf(TEXT(" (6) The media contains an Autorun.inf file in its root.\n"));
  297. }
  298. else
  299. {
  300. if (pcddevinfo->fHasMedia)
  301. {
  302. wprintf(TEXT(" (6) The media does *NOT* contain an Autorun.inf file.\n"));
  303. }
  304. }
  305. if (pcddevinfo->fHasDesktopINI)
  306. {
  307. wprintf(TEXT(" (7) The media contains an Desktop.ini file in its root.\n"));
  308. }
  309. if (pcddevinfo->fHasDVDMovie)
  310. {
  311. wprintf(TEXT(" (8) The media contains a DVD Movie.\n"));
  312. if (pcddevinfo->fHasAutorunINF)
  313. {
  314. wprintf(TEXT(" (8.1) But it also contains an Autorun.inf which\n"));
  315. wprintf(TEXT(" should take precedence when Autoplay'ing.\n"));
  316. }
  317. }
  318. if (fMMC2Features)
  319. {
  320. if (pcddevinfo->fMMC2)
  321. {
  322. wprintf(TEXT(" (9) Drive is MMC2 compliant, supported features (* = current):\n"));
  323. ProcessMMC2Features(pcddevinfo);
  324. }
  325. else
  326. {
  327. wprintf(TEXT(" (9) Drive is not MMC2 compliant, ignored /f flag.\n"));
  328. }
  329. }
  330. return S_OK;
  331. }
  332. extern "C"
  333. {
  334. int __cdecl wmain(int argc, wchar_t* argv[])
  335. {
  336. BOOL fDoIt = FALSE;
  337. BOOL fDoHelp = TRUE;
  338. BOOL fMMC2Features = FALSE;
  339. if (argc > 1)
  340. {
  341. if (!lstrcmpi(argv[1], TEXT("/?")) ||
  342. !lstrcmpi(argv[1], TEXT("-?")))
  343. {
  344. }
  345. else
  346. {
  347. if (!lstrcmpi(argv[1], TEXT("/f")) ||
  348. !lstrcmpi(argv[1], TEXT("-f")))
  349. {
  350. fDoIt = TRUE;
  351. fMMC2Features = TRUE;
  352. fDoHelp = FALSE;
  353. }
  354. }
  355. }
  356. else
  357. {
  358. fDoIt = TRUE;
  359. }
  360. if (fDoIt)
  361. {
  362. HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  363. if (SUCCEEDED(hr))
  364. {
  365. IHardwareDevices* pihwdevs = NULL;
  366. hr = CoCreateInstance(CLSID_HardwareDevices, NULL,
  367. CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IHardwareDevices, &pihwdevs));
  368. if (SUCCEEDED(hr))
  369. {
  370. {
  371. IHardwareDevicesVolumesEnum* penum;
  372. hr = pihwdevs->EnumVolumes(HWDEV_GETCUSTOMPROPERTIES, &penum);
  373. if (SUCCEEDED(hr))
  374. {
  375. VOLUMEINFO volinfo = {0};
  376. while (SUCCEEDED(hr = penum->Next(&volinfo)) && (S_FALSE != hr))
  377. {
  378. if (HWDTS_CDROM == volinfo.dwDriveType)
  379. {
  380. cddevinfo[ccddevinfo].fMMC2 = (volinfo.dwDriveCapability & HWDDC_CAPABILITY_SUPPORTDETECTION);
  381. cddevinfo[ccddevinfo].fHasMedia = (volinfo.dwMediaState & HWDMS_PRESENT);
  382. cddevinfo[ccddevinfo].fMediaFormatted = (volinfo.dwMediaState & HWDMS_FORMATTED);
  383. cddevinfo[ccddevinfo].fHasAudioTracks = (volinfo.dwMediaCap & HWDMC_HASAUDIOTRACKS);
  384. cddevinfo[ccddevinfo].fHasData = (volinfo.dwMediaCap & HWDMC_HASDATATRACKS);
  385. cddevinfo[ccddevinfo].fHasAutorunINF = (volinfo.dwMediaCap & HWDMC_HASAUTORUNINF);
  386. cddevinfo[ccddevinfo].fHasDesktopINI = (volinfo.dwMediaCap & HWDMC_HASDESKTOPINI);
  387. cddevinfo[ccddevinfo].fHasDVDMovie = (volinfo.dwMediaCap & HWDMC_HASDVDMOVIE);
  388. cddevinfo[ccddevinfo].dwMediaType = (volinfo.dwMediaCap & HWDMC_CDTYPEMASK);
  389. cddevinfo[ccddevinfo].dwDriveType = (volinfo.dwDriveCapability & HWDDC_CDTYPEMASK);
  390. hr = SafeStrCpyN(cddevinfo[ccddevinfo].szFileSystem, volinfo.pszFileSystem, ARRAYSIZE(cddevinfo[ccddevinfo].szFileSystem));
  391. if (FAILED(hr))
  392. {
  393. SafeStrCpyN(cddevinfo[ccddevinfo].szFileSystem, TEXT("ERROR"), ARRAYSIZE(cddevinfo[ccddevinfo].szFileSystem));
  394. }
  395. hr = SafeStrCpyN(cddevinfo[ccddevinfo].szVolGUID, volinfo.pszVolumeGUID, ARRAYSIZE(cddevinfo[ccddevinfo].szVolGUID));
  396. if (FAILED(hr))
  397. {
  398. SafeStrCpyN(cddevinfo[ccddevinfo].szVolGUID, TEXT("ERROR"), ARRAYSIZE(cddevinfo[ccddevinfo].szVolGUID));
  399. }
  400. hr = SafeStrCpyN(cddevinfo[ccddevinfo].szVolDeviceID, volinfo.pszDeviceIDVolume, ARRAYSIZE(cddevinfo[ccddevinfo].szVolDeviceID));
  401. if (FAILED(hr))
  402. {
  403. SafeStrCpyN(cddevinfo[ccddevinfo].szVolDeviceID, TEXT("ERROR"), ARRAYSIZE(cddevinfo[ccddevinfo].szVolDeviceID));
  404. }
  405. ++ccddevinfo;
  406. }
  407. }
  408. penum->Release();
  409. }
  410. }
  411. if (ccddevinfo)
  412. {
  413. if (1 == ccddevinfo)
  414. {
  415. wprintf(TEXT("\n Found 1 CD Drive\n"));
  416. }
  417. else
  418. {
  419. wprintf(TEXT("\n Found %d CD Drives\n"), ccddevinfo);
  420. }
  421. }
  422. else
  423. {
  424. wprintf(TEXT("\n Did not find any CD Drive. If there is a CD drive then\n"));
  425. wprintf(TEXT(" you found a bug in the Shell Service.\n"));
  426. }
  427. {
  428. IHardwareDevicesMountPointsEnum* penum;
  429. hr = pihwdevs->EnumMountPoints(&penum);
  430. if (SUCCEEDED(hr))
  431. {
  432. LPWSTR pszMountPoint;
  433. LPWSTR pszDeviceIDVolume;
  434. while (SUCCEEDED(hr = penum->Next(
  435. &pszMountPoint, &pszDeviceIDVolume)) &&
  436. (S_FALSE != hr))
  437. {
  438. for (DWORD dw = 0; dw < ccddevinfo; ++dw)
  439. {
  440. if (!lstrcmpi(pszDeviceIDVolume, cddevinfo[dw].szVolDeviceID))
  441. {
  442. ProcessCDInfo(pszMountPoint, &cddevinfo[dw], fMMC2Features);
  443. }
  444. }
  445. }
  446. penum->Release();
  447. }
  448. }
  449. }
  450. if (ccddevinfo)
  451. {
  452. wprintf(TEXT("\n If any of the above is false, you found a bug in the Shell Service.\n"));
  453. if (fMMC2Features)
  454. {
  455. wprintf(TEXT(" However, if the MMC2 feature information is false, there is\n"));
  456. wprintf(TEXT(" probably a problem with the drive.\n"));
  457. }
  458. }
  459. CoUninitialize();
  460. }
  461. }
  462. else
  463. {
  464. if (fDoHelp)
  465. {
  466. wprintf(TEXT("\nBasic diagnostic of CD/DVD drives\n"));
  467. wprintf(TEXT("\nCDDIAG.EXE [/f]\n\n"));
  468. wprintf(TEXT(" /f Displays the MMC2 feature supported by the drive.\n\n"));
  469. }
  470. }
  471. return 0;
  472. }
  473. }