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.

845 lines
25 KiB

  1. // DvdCheck.cpp : Determine if DVD exists on a system. Differentiate between MCI and DirectShow Solutions
  2. //
  3. // Modified 3/31/99 by Steve Rowe (strowe)
  4. // Modified 2000/10/11 by Glenn Evans (glenne) to hunt down version & company names & MCI solutions
  5. //
  6. #include <streams.h>
  7. #include <windows.h>
  8. #include <initguid.h>
  9. #include <uuids.h>
  10. #include "DvdDetect.h"
  11. #include "crc32.h"
  12. DVDResult::DVDResult()
  13. : m_pName( NULL )
  14. , m_pCompanyName( NULL )
  15. , m_Version( 0 )
  16. , m_fFound( false )
  17. , m_dwCRC( 0 )
  18. {
  19. SetName( TEXT("") );
  20. SetCompanyName( TEXT("") );
  21. }
  22. DVDResult::~DVDResult()
  23. {
  24. delete [] m_pName;
  25. delete [] m_pCompanyName;
  26. }
  27. static TCHAR* CloneString( const TCHAR* pStr )
  28. {
  29. if( pStr ) {
  30. TCHAR* pNew = new TCHAR[ lstrlen( pStr ) +1 ];
  31. if( pNew ) {
  32. lstrcpy( pNew, pStr );
  33. return pNew;
  34. }
  35. }
  36. return NULL;
  37. }
  38. void DVDResult::SetVersion( UINT64 version)
  39. {
  40. m_Version = version;
  41. }
  42. void DVDResult::SetCRC( DWORD CRC)
  43. {
  44. m_dwCRC = CRC;
  45. }
  46. void DVDResult::SetFound( bool fFound)
  47. {
  48. m_fFound = fFound;
  49. }
  50. void DVDResult::SetName( const TCHAR* pName )
  51. {
  52. delete [] m_pName;
  53. m_pName = CloneString( pName );
  54. }
  55. void DVDResult::SetCompanyName( const TCHAR* pName )
  56. {
  57. delete [] m_pCompanyName;
  58. m_pCompanyName = CloneString( pName );
  59. }
  60. // NOTE: strmiids.lib is necessary for this to compile.
  61. // This is the KSProxy GUID.
  62. DEFINE_GUID(DVD_KSPROXY, 0x17CCA71BL, 0xECD7, 0x11D0, 0xB9, 0x08, 0x00, 0xA0, 0xC9, 0x22,
  63. 0x31, 0x96);
  64. //
  65. // More or less lifted from the w2k SFP code
  66. //
  67. struct LANGANDCODEPAGE {
  68. WORD wLanguage;
  69. WORD wCodePage;
  70. };
  71. static HRESULT GetFileVersion (const TCHAR* pszFile, // file
  72. DVDResult& result
  73. )
  74. {
  75. DWORD dwSize, dwHandle;
  76. VS_FIXEDFILEINFO *pFixedVersionInfo;
  77. DWORD dwVersionInfoSize;
  78. DWORD dwReturnCode;
  79. dwSize = GetFileVersionInfoSize( const_cast<TCHAR *>(pszFile), &dwHandle);
  80. HRESULT hr = S_OK;
  81. // .txt and .inf, etc files might not have versions
  82. if( dwSize == 0 )
  83. {
  84. dwReturnCode = GetLastError();
  85. hr = E_FAIL;
  86. } else {
  87. LPVOID pVersionInfo= new BYTE [dwSize];
  88. if( NULL == pVersionInfo) {
  89. hr = E_OUTOFMEMORY;
  90. } else {
  91. if( !GetFileVersionInfo( const_cast<TCHAR *>(pszFile), dwHandle, dwSize, pVersionInfo ) ) {
  92. dwReturnCode = GetLastError();
  93. DbgLog((LOG_ERROR, 1, TEXT("Error in GetFileVersionInfo for %s. ec=%d"),
  94. pszFile, dwReturnCode));
  95. hr = E_FAIL;
  96. } else {
  97. if( !VerQueryValue( pVersionInfo,
  98. TEXT("\\"), // we need the root block
  99. (LPVOID *) &pFixedVersionInfo,
  100. (PUINT) &dwVersionInfoSize ) )
  101. {
  102. dwReturnCode = GetLastError();
  103. hr = E_FAIL;
  104. } else {
  105. result.SetVersion( ((UINT64(pFixedVersionInfo->dwFileVersionMS))<<32) + pFixedVersionInfo->dwFileVersionLS);
  106. }
  107. // Structure used to store enumerated languages and code pages.
  108. // Read the list of languages and code pages.
  109. LANGANDCODEPAGE *lpTranslate;
  110. UINT cbTranslate;
  111. if( VerQueryValue(pVersionInfo,
  112. TEXT("\\VarFileInfo\\Translation"),
  113. (LPVOID*)&lpTranslate,
  114. &cbTranslate) )
  115. {
  116. // Read the file description for each language and code page.
  117. for( DWORD i=0; i < (cbTranslate/sizeof(struct LANGANDCODEPAGE)); i++ )
  118. {
  119. TCHAR SubBlock[512];
  120. // Retrieve file description for language and code page "i".
  121. TCHAR* lpBuffer;
  122. UINT dwBytes;
  123. wsprintf( SubBlock,
  124. TEXT("\\StringFileInfo\\%04x%04x\\CompanyName"),
  125. lpTranslate[i].wLanguage,
  126. lpTranslate[i].wCodePage);
  127. if( VerQueryValue(pVersionInfo,
  128. SubBlock,
  129. (VOID **)&lpBuffer,
  130. &dwBytes) )
  131. {
  132. result.SetCompanyName( lpBuffer );
  133. }
  134. }
  135. }
  136. }
  137. delete [] pVersionInfo;
  138. }
  139. }
  140. return hr;
  141. }
  142. static bool EndsIn( const TCHAR* pStr, const TCHAR* pExtension )
  143. {
  144. int iExtLen = lstrlen( pExtension );
  145. int iStrLen = lstrlen( pStr );
  146. if( iStrLen >= iExtLen ) {
  147. return lstrcmp( &pStr[iStrLen - iExtLen], pExtension ) == 0;
  148. } else {
  149. return false;
  150. }
  151. }
  152. #define MAKE_VER_NUM( v1, v2, v3, v4 ) (((UINT64(v1) << 16 | (v2) )<<16 | (v3) ) << 16 | (v4) )
  153. static void StrCpy( TCHAR* pDest, WCHAR* pSrc, int iDestSize )
  154. {
  155. #ifdef UNICODE
  156. lstrcpyn(pDest, pSrc, iDestSize );
  157. #else
  158. WideCharToMultiByte(
  159. CP_ACP,
  160. 0, // flags
  161. pSrc, // src
  162. -1, // cch
  163. pDest, // dest
  164. iDestSize, // cb
  165. 0, // lpDefaultChar
  166. 0); // lpUsedDefaultChar
  167. #endif
  168. }
  169. static HRESULT GetFilenameFromCLSID( const VARIANT& varFilterClsid, TCHAR szFilename[ MAX_PATH ] )
  170. {
  171. HRESULT hr = E_FAIL;
  172. TCHAR szKey[512];
  173. TCHAR szQuery[512];
  174. // Convert BSTR to string and free variant storage
  175. StrCpy( szQuery, varFilterClsid.bstrVal, sizeof( szQuery )/ sizeof( szQuery[0]) );
  176. SysFreeString(varFilterClsid.bstrVal);
  177. // Create key name for reading filename registry
  178. wsprintf(szKey, TEXT("Software\\Classes\\CLSID\\%s\\InprocServer32\0"),
  179. szQuery);
  180. // Variables needed for registry query
  181. HKEY hkeyFilter=0;
  182. DWORD dwSize=MAX_PATH;
  183. int rc=0;
  184. // Open the CLSID key that contains information about the filter
  185. rc = RegOpenKey(HKEY_LOCAL_MACHINE, szKey, &hkeyFilter);
  186. if (rc == ERROR_SUCCESS)
  187. {
  188. rc = RegQueryValueEx(hkeyFilter, NULL, // Read (Default) value
  189. NULL, NULL, (BYTE *)szFilename, &dwSize);
  190. if (rc == ERROR_SUCCESS)
  191. {
  192. hr = S_OK;
  193. }
  194. rc = RegCloseKey(hkeyFilter);
  195. }
  196. return hr;
  197. }
  198. static const TCHAR* FilenameFromPathname( const TCHAR* pStr )
  199. {
  200. const TCHAR* pSlash=0;
  201. const TCHAR* pOrig = pStr;
  202. while( *pStr ) {
  203. if( *pStr == TEXT('\\') ) {
  204. pSlash = pStr;
  205. }
  206. pStr++;
  207. }
  208. if( pSlash ) {
  209. return pSlash +1;
  210. } else {
  211. return pOrig;
  212. }
  213. }
  214. static bool GetFileLength( const TCHAR* pszPathname, ULONGLONG* pullFileSize )
  215. {
  216. WIN32_FIND_DATA wInfo;
  217. HANDLE hInfo = FindFirstFile( pszPathname, &wInfo );
  218. FindClose(hInfo);
  219. if (hInfo!=INVALID_HANDLE_VALUE) {
  220. if( pullFileSize ) {
  221. *pullFileSize = (ULONGLONG(wInfo.nFileSizeHigh) << 32) | wInfo.nFileSizeLow;
  222. }
  223. return true;
  224. } else {
  225. if( pullFileSize ) {
  226. *pullFileSize = 0;
  227. }
  228. return false;
  229. }
  230. }
  231. static DWORD CRCFromFile( const TCHAR* pFile )
  232. {
  233. ULONGLONG length;
  234. DWORD dwCRC = 0;
  235. if( GetFileLength( pFile, &length )) {
  236. BYTE* pBuffer = new BYTE[ULONG(length)];
  237. if( pBuffer ) {
  238. HANDLE hFile = ::CreateFile( pFile,
  239. GENERIC_READ, FILE_SHARE_READ,
  240. NULL, OPEN_EXISTING,
  241. FILE_ATTRIBUTE_NORMAL, NULL);
  242. if( hFile != INVALID_HANDLE_VALUE ) {
  243. DWORD dwActual;
  244. if( ReadFile( hFile, pBuffer, ULONG(length), &dwActual, NULL ) ) {
  245. dwCRC=CRC32( pBuffer, ULONG(length));
  246. }
  247. CloseHandle( hFile );
  248. }
  249. delete [] pBuffer;
  250. }
  251. }
  252. return dwCRC;
  253. }
  254. static HRESULT AddSWFilter( IMoniker* pMon, DVDResult& result )
  255. {
  256. IPropertyBag *pPropBag;
  257. HRESULT hr = pMon->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropBag);
  258. if(SUCCEEDED(hr))
  259. {
  260. CLSID filterCLSID;
  261. HRESULT hrGotFilename=E_FAIL;
  262. TCHAR szFilename[ MAX_PATH ];
  263. // open clsid/{filter-clsid} key
  264. VARIANT varbstrClsid;
  265. varbstrClsid.vt = VT_BSTR;
  266. varbstrClsid.bstrVal = 0;
  267. hr = pPropBag->Read(L"CLSID", &varbstrClsid, 0);
  268. if(SUCCEEDED(hr)) {
  269. ASSERT(varbstrClsid.vt == VT_BSTR);
  270. WCHAR *strFilter = varbstrClsid.bstrVal;
  271. if (CLSIDFromString(varbstrClsid.bstrVal, &filterCLSID) == S_OK) {
  272. }
  273. hrGotFilename = GetFilenameFromCLSID( varbstrClsid, szFilename );
  274. SysFreeString(varbstrClsid.bstrVal);
  275. }
  276. pPropBag->Release();
  277. if ( DVD_KSPROXY == filterCLSID || CLSID_AVIDec == filterCLSID ) {
  278. ; // ignore this filter if it is the AVI Decompressor or KSProxy
  279. } else {
  280. if( S_OK == hrGotFilename ) {
  281. HRESULT hres = GetFileVersion( szFilename, result );
  282. if( S_OK == hres ) {
  283. result.SetName( FilenameFromPathname( szFilename ));
  284. result.SetFound( true );
  285. result.SetCRC( CRCFromFile( szFilename ));
  286. }
  287. }
  288. }
  289. } else {
  290. DbgLog((LOG_ERROR, 1, TEXT("ERROR: WARNING: BindToStorage failed"))) ;
  291. return E_UNEXPECTED;
  292. }
  293. return S_OK;
  294. }
  295. static HRESULT AddHWFilter( IMoniker* pMon, DVDResult& result )
  296. {
  297. IPropertyBag *pPropBag;
  298. HRESULT hr = pMon->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropBag);
  299. if(SUCCEEDED(hr))
  300. {
  301. result.SetFound( true );
  302. VARIANT var ;
  303. var.vt = VT_EMPTY ;
  304. hr = pPropBag->Read(L"FriendlyName", &var, 0) ;
  305. if (SUCCEEDED(hr))
  306. {
  307. DbgLog((LOG_TRACE, 5, TEXT("FriendlyName: %S"), var.bstrVal)) ;
  308. //
  309. // We have got a device under the required category. The proxy
  310. // for it is already instantiated. So add to the list of HW
  311. // decoders to be used for building the graph.
  312. //
  313. TCHAR szName[512];
  314. // Convert BSTR to string and free variant storage
  315. StrCpy( szName, var.bstrVal, sizeof( szName )/ sizeof( szName[0]) );
  316. result.SetName( szName );
  317. VariantClear(&var) ;
  318. }
  319. else
  320. {
  321. ASSERT(SUCCEEDED(hr)) ; // so that we know
  322. result.SetName( TEXT("generic HW") );
  323. }
  324. pPropBag->Release();
  325. } else {
  326. DbgLog((LOG_ERROR, 1, TEXT("ERROR: WARNING: BindToStorage failed"))) ;
  327. return E_UNEXPECTED;
  328. }
  329. return S_OK;
  330. }
  331. // Check if there are any SW DVD Decoders
  332. static HRESULT SWCheck(DVDResult& result)
  333. {
  334. HRESULT hres = S_OK; // result for the function
  335. HRESULT hr; // temporary result...
  336. // Create filter mapper to find software decoders
  337. IFilterMapper2 * pMapper ; // filter mapper object pointer
  338. hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC,
  339. IID_IFilterMapper2, (LPVOID *)&pMapper) ;
  340. if (FAILED(hr) || NULL == pMapper)
  341. {
  342. DbgLog((LOG_ERROR, 0,
  343. TEXT("ERROR: Couldn't create class FilterMapper for DVD SW Dec category (Error 0x%lx)"),
  344. hr)) ;
  345. ASSERT( !"Can't create filtermapper" );
  346. return E_UNEXPECTED;
  347. }
  348. const UINT NUM_TYPES = 3; // the number of type/subtype pairs
  349. GUID types[NUM_TYPES * 2];
  350. types[0] = MEDIATYPE_MPEG2_PES;
  351. types[1] = MEDIASUBTYPE_MPEG2_VIDEO;
  352. types[2] = MEDIATYPE_DVD_ENCRYPTED_PACK;
  353. types[3] = MEDIASUBTYPE_MPEG2_VIDEO;
  354. types[4] = MEDIATYPE_Video;
  355. types[5] = MEDIASUBTYPE_MPEG2_VIDEO;
  356. IEnumMoniker *pEnumMon = NULL ;
  357. hr = pMapper->EnumMatchingFilters(&pEnumMon, 0, TRUE, MERIT_DO_NOT_USE+1,
  358. TRUE, NUM_TYPES, types, NULL, NULL, FALSE, TRUE, 0, NULL,
  359. NULL, NULL);
  360. if (FAILED(hr) || NULL == pEnumMon)
  361. {
  362. DbgLog((LOG_ERROR, 1, TEXT("ERROR: No matching filter enum found (Error 0x%lx)"), hr)) ;
  363. pMapper->Release();
  364. return E_UNEXPECTED;
  365. }
  366. // now we check if we have a solution.
  367. // we ignore the AVI decompressor and KSProxy CLSID's.
  368. ULONG ul ;
  369. IMoniker *pMon = NULL;
  370. while ( S_OK == pEnumMon->Next(1, &pMon, &ul) && 1 == ul)
  371. {
  372. hres = AddSWFilter( pMon, result );
  373. }
  374. // clean up after ourselves
  375. if (NULL != pEnumMon) {
  376. pEnumMon->Release();
  377. }
  378. if (NULL != pMapper) {
  379. pMapper->Release();
  380. }
  381. if( hres == S_OK && !result.Found()==false ) {
  382. return S_FALSE;
  383. } else {
  384. return hres;
  385. }
  386. } // end of SWCheck
  387. static TCHAR CharUpper( TCHAR c )
  388. {
  389. // see the docs on CharUpper, single char if upper address WORD is NULL
  390. return (TCHAR) CharUpper( (LPTSTR)c );
  391. }
  392. static void Truncate( TCHAR* pStr, const TCHAR* pTruncateAt )
  393. {
  394. int iTruncLen = lstrlen( pTruncateAt );
  395. int iStrLen = lstrlen( pStr );
  396. for( int i=0; i < iStrLen - iTruncLen; i++ ) {
  397. for( int j=0; j < iTruncLen; j++ ) {
  398. if( CharUpper( pStr[i+j] ) != pTruncateAt[j] ) {
  399. goto NextLoop;
  400. }
  401. }
  402. pStr[i+iTruncLen]=TEXT('\0');
  403. break;
  404. NextLoop:
  405. ;
  406. }
  407. }
  408. // Determine if there are any MCI DVD devices present
  409. static HRESULT MCICheck( DVDResult& result)
  410. {
  411. TCHAR lpRetString[255];
  412. LPCTSTR lpDefault = TEXT("*!*");
  413. GetPrivateProfileString(
  414. TEXT("mci"),
  415. TEXT("DVDVideo"),
  416. lpDefault,
  417. lpRetString,
  418. 255,
  419. TEXT("system.ini") );
  420. if (lstrcmp(lpRetString, lpDefault)) {// if they are not the same
  421. // truncate ret string to *.drv
  422. Truncate( lpRetString, TEXT(".DRV") );
  423. result.SetName( lpRetString );
  424. result.SetFound( true );
  425. // try to hunt down version info
  426. //
  427. // File is in system
  428. //
  429. // Create key name for reading filename registry
  430. TCHAR szPathname[MAX_PATH];
  431. GetSystemDirectory( szPathname, sizeof(szPathname)/sizeof(szPathname[0]));
  432. lstrcat( szPathname, TEXT("\\") );
  433. lstrcat( szPathname, lpRetString );
  434. HRESULT hres = GetFileVersion( szPathname, result );
  435. if( S_OK == hres ) {
  436. result.SetCRC( CRCFromFile( szPathname ));
  437. } else {
  438. GetWindowsDirectory( szPathname, sizeof(szPathname)/sizeof(szPathname[0]));
  439. lstrcat( szPathname, TEXT("\\") );
  440. lstrcat( szPathname, lpRetString );
  441. hres = GetFileVersion( szPathname, result );
  442. if( S_OK == hres ) {
  443. result.SetCRC( CRCFromFile( szPathname ));
  444. } else {
  445. ASSERT(!"Can't find DVD MCI filename");
  446. return S_FALSE;
  447. }
  448. }
  449. return hres;
  450. } else {
  451. return S_FALSE; // can't really fail this check
  452. }
  453. } // end of MCICheck
  454. // Check if there are any HW DVD Decoders
  455. // we use DevEnum to check for DVDHWDecodersCategory
  456. static HRESULT HWCheck(DVDResult& result)
  457. {
  458. ICreateDevEnum *pCreateDevEnum ;
  459. HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
  460. IID_ICreateDevEnum, (void**)&pCreateDevEnum) ;
  461. if (FAILED(hr) || NULL == pCreateDevEnum)
  462. {
  463. DbgLog((LOG_ERROR, 0, TEXT("WARNING: Couldn't create system dev enum (Error 0x%lx)"), hr)) ;
  464. // need to put some better error handling in here
  465. return E_UNEXPECTED;
  466. }
  467. IEnumMoniker *pEnumMon ;
  468. hr = pCreateDevEnum->CreateClassEnumerator(CLSID_DVDHWDecodersCategory,
  469. &pEnumMon, 0) ;
  470. pCreateDevEnum->Release() ;
  471. if (S_FALSE == hr )
  472. {
  473. // should indicate that we have no enumerator but not an error because
  474. // this means there are no such devices.
  475. DbgLog((LOG_ERROR, 0,
  476. TEXT("WARNING: Couldn't create class enum for DVD HW Dec category (Error 0x%lx)"),
  477. hr)) ;
  478. return S_FALSE;
  479. }
  480. if (FAILED(hr) || NULL == pEnumMon)
  481. {
  482. DbgLog((LOG_ERROR, 0,
  483. TEXT("ERROR: Couldn't create class enum for DVD HW Dec category (Error 0x%lx)"),
  484. hr)) ;
  485. return E_UNEXPECTED;
  486. }
  487. hr = pEnumMon->Reset() ;
  488. ULONG ul ;
  489. IMoniker *pMon ;
  490. if (S_OK == pEnumMon->Next(1, &pMon, &ul) && 1 == ul) {
  491. // Always comes back as WDM generic Filter Proxy (ksproxy.ax)
  492. hr = AddHWFilter( pMon, result );
  493. }
  494. if (NULL != pEnumMon) {
  495. pEnumMon->Release();
  496. }
  497. return result.Found() ? S_OK : S_FALSE;
  498. } // end of HWCheck
  499. HRESULT DVDDetect( DVDResult& mci, DVDResult& sw, DVDResult& hw )
  500. // Primary entry point - will determine if any DVD is present
  501. {
  502. HRESULT hres = CoInitialize(NULL);
  503. if( SUCCEEDED( hres )) {
  504. //
  505. // DSHOW HARDWARE CHECK
  506. //
  507. hres = HWCheck(hw);
  508. if( SUCCEEDED( hres)) {
  509. //
  510. // DSHOW SOFTWARE CHECK
  511. //
  512. hres = SWCheck(sw);
  513. if( SUCCEEDED( hres)) {
  514. //
  515. // MCI CHECK
  516. //
  517. hres = MCICheck(mci);
  518. }
  519. }
  520. CoUninitialize();
  521. } else {
  522. ASSERT( !"Can't CoInit" );
  523. }
  524. return hres;
  525. }
  526. // Decoder exe CompanyName version crc
  527. //
  528. // Ravisent 2000 "QIDVDF.AX" "RAVISENT Technologies Inc." 1.2.0.115 0x786cd58f
  529. // Ravisent (ATIPlayer) "QIDVDF.AX" "Quadrant International, Inc." 1.1.0.37 0x41a24b10
  530. // Intervideo 1.31 (WinDVD) "IVIVIDEO.AX" " InterVideo Inc." 1.0.0.1 0xadf3b652 Will have to get version through registry
  531. // Intervideo 2.111 (WinDVD) "IVIVIDEO.AX" " InterVideo Inc." 1.0.0.1 0x42b020f8
  532. // Mediamatics "DVD Express AV Decoder.dll" "Mediamatics, Inc." 5.0.0.15
  533. // 5.0.0.38
  534. // 5.0.0.42
  535. // 5.0.0.45
  536. // 5.0.0.75 0xdf2fa5df
  537. // 5.0.0.97
  538. //
  539. // MGI (SoftDVDMax) "ZVIDFLT.AX" "MGI Software Corp." 1.0.0.1 0x4d91884f
  540. //
  541. // MGI Build 00089 "DVDVideo.ax" "MGI Software Corp." 1.8.6.0 0x6bc2c0d4 can't find setup.ddl in Win2k, causes error in Whistler
  542. // MGI Build 33959 "zvidflt.ax" "MGI Software Corp." 1.0.0.1 0x0482b35b works fine in both win2k and whistler
  543. // MGI karaoke "zvidflt.ax" "MGI Software Corp." 1.0.0.1 0x4d91884f no disk in drive error on whistler, no windows 2000 compatible decoder on win2k
  544. // MGI 4.00.0001 "zvidflt.ax" "MGI Software Corp." 1.0.0.1 0xd6a7abc3 works fin in both Win2k and Whistler
  545. // MGI 5.0DH "zvidflt.ax" "MGI Software Corp." 1.0.0.1 0xd66f9452 works fine in both win2k and whistler
  546. //
  547. // Zoran 3.07.01 "Softpeg.drv" "" 0.0.0.0 0x0 Win2k cant install, whistler says software ot configured to run on your machine
  548. // Zoran 3.25.02 "zvidflt.ax" "Zoran/CompCore Corp." 1.0.0.0 0x1e44e3d6 DVD Authentication error in whistler, no video or error in win2k
  549. // Zoran 3.25.03 "Softpeg.drv" "" 0.0.0.0 0x0 drive not ready or no disk in drive on both win2k and whistler
  550. // Cyberlink PowerDVD 2.50 "clvsd.ax" "CyberLink Corp." 2.0.0.0 0x964ef3b9 Generates errors in all dshow players in both Win2k and Whistler
  551. // Cyberlink PowerDVD 2.5.5 "clvsd.ax "CyberLink Corp." 2.0.0.0 0x964ef3b9 Works fine in Whistler, Win2k there's no video
  552. #define MAKE_VER_NUM( v1, v2, v3, v4 ) (((UINT64(v1) << 16 | (v2) )<<16 | (v3) ) << 16 | (v4) )
  553. static bool AreEquivalent( const char* pStr1, const char* pStr2 )
  554. {
  555. return lstrcmpiA( pStr1, pStr2 ) ==0;
  556. }
  557. static bool AreEquivalent( const WCHAR* pStr1, const WCHAR* pStr2 )
  558. {
  559. return lstrcmpiW( pStr1, pStr2 ) ==0;
  560. }
  561. DecoderVendor DVDResult::GetVendor() const
  562. {
  563. const TCHAR* pName = GetCompanyName();
  564. //TBD: vendor_NEC
  565. if( AreEquivalent( pName, TEXT("Mediamatics, Inc.") )) {
  566. return vendor_MediaMatics;
  567. } else if( AreEquivalent( pName, TEXT(" InterVideo Inc.")) ) {
  568. return vendor_Intervideo;
  569. } else if( AreEquivalent( pName, TEXT("RAVISENT Technologies Inc.")) ||
  570. AreEquivalent( pName, TEXT("Quadrant International, Inc.")) )
  571. {
  572. return vendor_Ravisent;
  573. } else if( AreEquivalent( pName, TEXT("CyberLink Corp.")) ) {
  574. return vendor_CyberLink;
  575. } else if( AreEquivalent( pName, TEXT("MGI Software Corp.")) ||
  576. AreEquivalent( pName, TEXT("Zoran/CompCore Corp.")) )
  577. {
  578. return vendor_MGI;
  579. } else {
  580. return vendor_Unknown;
  581. }
  582. }
  583. #if 0
  584. //
  585. // only valid AFTER GUI setup and at first boot
  586. //
  587. static bool IsWin9xUpgrade()
  588. {
  589. // The answer file has the answer (system32\$winnt$.inf)
  590. // [data]
  591. // win9xupgrade=yes
  592. TCHAR dir[MAX_PATH];
  593. UINT uiResult = GetWindowsDirectory( dir, sizeof(dir)/sizeof(dir[0]) );
  594. if( uiResult > 0 ) {
  595. lstrcat( dir, TEXT("\\system32\\$winnt$.inf") );
  596. TCHAR buffer[100];
  597. buffer[0]=0;
  598. DWORD dwResult = GetPrivateProfileString(
  599. TEXT("data"), // section name
  600. TEXT("win9xupgrade"), // key name
  601. TEXT(""), // default string
  602. buffer, // destination buffer
  603. sizeof(buffer)/sizeof(buffer[0]), // size of destination buffer in TCHARS
  604. dir );// initialization file name
  605. bool fResult = ( dwResult > 0 ) && AreEquivalent( buffer, TEXT("yes") );
  606. return fResult;
  607. } else {
  608. return true;
  609. }
  610. }
  611. #endif
  612. static bool DoesAspi32Exist( bool fWillBe9xUpgrade )
  613. {
  614. if( fWillBe9xUpgrade ) {
  615. return false;
  616. } else {
  617. TCHAR szPathname[MAX_PATH];
  618. GetWindowsDirectory( szPathname, sizeof(szPathname)/sizeof(szPathname[0]));
  619. //
  620. // NOTE: this will fail under Win9x (since its system\drivers) implying there isn't going
  621. // to be an aspi32 under Whislter (blocked & deleted). So under 9x, we return true
  622. // and under Whistler their apps only survive if its around.
  623. //
  624. lstrcat( szPathname, TEXT("\\system32\\drivers\\aspi32.sys") );
  625. ULONGLONG ullLength;
  626. return GetFileLength( szPathname, &ullLength );
  627. }
  628. }
  629. bool DVDResult::ShouldUpgrade( bool fWillBe9xUpgrade ) const
  630. {
  631. switch( GetVendor() ) {
  632. case vendor_MediaMatics:
  633. return GetVersion() <= MAKE_VER_NUM( 5,1,0,5 ); // TBD: arbitrary right now for debugging purposes
  634. // return GetVersion() <= MAKE_VER_NUM( 5,0,0,15 );
  635. case vendor_Intervideo:
  636. {
  637. // so far all versions require aspi32
  638. if( GetVersion() <= MAKE_VER_NUM(1,0,0,1 )) {
  639. bool fAspiExists = DoesAspi32Exist(fWillBe9xUpgrade);
  640. if( !fAspiExists ) {
  641. return true;
  642. }
  643. }
  644. // all unknown versions are 1.0.0.1
  645. // We correct the known ones to numbers above that
  646. switch( GetCRC()) {
  647. case 0xadf3b652: // 1.31.0.0
  648. return false;
  649. case 0x42b020f8: // 2.111.0.0
  650. return false;
  651. default:
  652. return true;
  653. }
  654. }
  655. default:
  656. return false;
  657. }
  658. }
  659. DVDResult* DVDDetectBuffer::Detect()
  660. {
  661. if(SUCCEEDED(DVDDetect( mci, sw, hw )))
  662. {
  663. const DVDResult* pResult;
  664. if( sw.Found()) {
  665. return &sw;
  666. } else if( mci.Found()) {
  667. return &mci;
  668. } else {
  669. // hardware, so we don't care about the decoder OR the app for now
  670. return NULL;
  671. }
  672. }
  673. return NULL;
  674. }
  675. HRESULT DVDDetectBuffer::DetectAll()
  676. {
  677. return DVDDetect( mci, sw, hw );
  678. }
  679. #define RUN_KEY TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run")
  680. static bool RegSetRunValue( const TCHAR* pString, const TCHAR* pValue )
  681. {
  682. HKEY hRunKey;
  683. LONG lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, RUN_KEY, 0, KEY_SET_VALUE, &hRunKey) ;
  684. if (ERROR_SUCCESS == lRet) {
  685. lRet = RegSetValueEx(hRunKey, pString, 0, REG_SZ, (BYTE *)pValue, sizeof(pValue[0])*(lstrlen(pValue)+1) );
  686. RegCloseKey( hRunKey );
  687. return ( ERROR_SUCCESS == lRet);
  688. }
  689. return false;
  690. }
  691. static bool RegRunDeleteValue( const TCHAR* pString )
  692. {
  693. HKEY hRunKey;
  694. LONG lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RUN_KEY, 0, KEY_SET_VALUE, &hRunKey) ;
  695. if (ERROR_SUCCESS == lRet) {
  696. lRet = RegDeleteValue( hRunKey, pString ) ;
  697. // either we nuked it or it didn't exist in the first place, either way its gone
  698. bool fWorked = ( lRet == ERROR_SUCCESS || lRet == ERROR_FILE_NOT_FOUND );
  699. ASSERT( fWorked ) ;
  700. RegCloseKey( hRunKey );
  701. return fWorked;
  702. }
  703. return false;
  704. }
  705. #define DVDUPGRADE_NAME TEXT("DVDUpgrade")
  706. bool DVDDetectSetupRun::Remove()
  707. {
  708. bool fOk = RegRunDeleteValue( DVDUPGRADE_NAME );
  709. ASSERT(fOk);
  710. return fOk;
  711. }
  712. bool DVDDetectSetupRun::Add()
  713. {
  714. bool fOk;
  715. fOk = RegSetRunValue( DVDUPGRADE_NAME, TEXT("DVDUpgrd.exe /upgrade"));
  716. ASSERT(fOk);
  717. return fOk;
  718. }
  719. extern "C" BOOL
  720. IsDvdPresent (
  721. VOID
  722. )
  723. {
  724. DVDDetectBuffer buffer;
  725. const DVDResult* pResult = buffer.Detect();
  726. if( pResult ) {
  727. const DVDResult& result = *pResult;
  728. // at this point the $winnt$.inf doesn't exist, so we must assume
  729. // that we're bing called from the win95upg
  730. const bool fInWin9xUpgrade = true;
  731. return result.ShouldUpgrade(fInWin9xUpgrade);
  732. }
  733. return false;
  734. }