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.

830 lines
26 KiB

  1. ///////////////////////////////////////////////////////////
  2. //
  3. //
  4. // HHFinder.cpp : Implementation of CHHFinder
  5. //
  6. //
  7. #include "header.h"
  8. #ifdef _DEBUG
  9. #undef THIS_FILE
  10. static const CHAR THIS_FILE[] = __FILE__;
  11. #endif
  12. #include "resource.h"
  13. #include "strtable.h"
  14. #include "atlinc.h" // includes for ATL.
  15. #include "HHFinder.h"
  16. #include "cdlg.h"
  17. #include "wwheel.h"
  18. #include "secwin.h"
  19. // Used to lock toplevel windows before displaying a dialog.
  20. #include "lockout.h"
  21. // defines
  22. #define HH_VERSION_1_3 // define this is build HH 1.3 or newer
  23. ///////////////////////////////////////////////////////////
  24. //
  25. // Internal Structure Definition
  26. //
  27. ///////////////////////////////////////////////////////////
  28. //
  29. // HHREMOVEABLE
  30. //
  31. typedef struct _hhremovable
  32. {
  33. UINT uiDriveType;
  34. PCSTR pszDriveLetter;
  35. PCSTR pszVolumeName;
  36. PSTR* ppszLocation;
  37. } HHREMOVABLE;
  38. ///////////////////////////////////////////////////////////
  39. //
  40. // Globals
  41. //
  42. #ifdef _DEBUG
  43. static BOOL g_bShowMessage = TRUE;
  44. #endif
  45. ///////////////////////////////////////////////////////////
  46. //
  47. // Prototypes
  48. //
  49. INT_PTR CALLBACK RemovableMediaDialogProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
  50. ///////////////////////////////////////////////////////////
  51. //
  52. // Functions
  53. //
  54. ///////////////////////////////////////////////////////////
  55. //
  56. // GetPathAndFileName
  57. //
  58. PCSTR GetPathAndFileName( PCSTR pszFilename, PSTR pszPathBuffer, PSTR pszFilenameBuffer )
  59. {
  60. CHAR szPathname[MAX_PATH];
  61. PSTR pszFile;
  62. GetFullPathName( pszFilename, sizeof(szPathname), szPathname, &pszFile );
  63. lstrcpyn( pszPathBuffer, szPathname, (int)(((DWORD_PTR)pszFile) - ((DWORD_PTR)&szPathname)) );
  64. strcpy( pszFilenameBuffer, pszFile );
  65. return( pszFilename );
  66. }
  67. /////////////////////////////////////////////////////////////////////////////
  68. // CLocationNode
  69. class CLocationNode {
  70. public:
  71. CLocationNode::CLocationNode( PCSTR pszLocationId )
  72. {
  73. m_pszLocationId = new CHAR[strlen(pszLocationId)+1];
  74. strcpy( (PSTR) m_pszLocationId, pszLocationId );
  75. m_pNext = NULL;
  76. }
  77. CLocationNode::~CLocationNode( )
  78. {
  79. delete [] (PSTR) m_pszLocationId;
  80. }
  81. CLocationNode* GetNext() { return m_pNext; }
  82. CLocationNode* SetNext( CLocationNode* pNext ) { m_pNext = pNext; return m_pNext; }
  83. PCSTR GetLocationId() { return m_pszLocationId; }
  84. private:
  85. PCSTR m_pszLocationId;
  86. CLocationNode* m_pNext;
  87. };
  88. /////////////////////////////////////////////////////////////////////////////
  89. // CLocationList
  90. class CLocationList {
  91. public:
  92. CLocationList::CLocationList()
  93. {
  94. m_iCount = 0;
  95. m_pHead = NULL;
  96. m_pTail = NULL;
  97. }
  98. CLocationList::~CLocationList()
  99. {
  100. Free();
  101. }
  102. void CLocationList::Free()
  103. {
  104. CLocationNode* pNode = m_pHead;
  105. for( int i=0; i < m_iCount; i++ ) {
  106. CLocationNode* pNodeNext = pNode->GetNext();
  107. delete pNode;
  108. pNode = pNodeNext;
  109. }
  110. m_iCount = 0;
  111. m_pHead = NULL;
  112. m_pTail = NULL;
  113. }
  114. CLocationNode* CLocationList::Add( PCSTR pszLocationId )
  115. {
  116. CLocationNode* pNode = new CLocationNode( pszLocationId );
  117. if( m_iCount )
  118. m_pTail->SetNext( pNode );
  119. else
  120. m_pHead = pNode;
  121. m_pTail = pNode;
  122. m_iCount++;
  123. return pNode;
  124. }
  125. CLocationNode* CLocationList::Find( PCSTR pszLocationId )
  126. {
  127. CLocationNode* pNode = m_pHead;
  128. for( int i=0; i < m_iCount; i++ ) {
  129. if( strcmp( pszLocationId, pNode->GetLocationId() ) == 0 )
  130. break;
  131. CLocationNode* pNodeNext = pNode->GetNext();
  132. pNode = pNodeNext;
  133. }
  134. return pNode;
  135. }
  136. private:
  137. int m_iCount;
  138. CLocationNode* m_pHead;
  139. CLocationNode* m_pTail;
  140. };
  141. CLocationList g_LocationSkipList;
  142. /////////////////////////////////////////////////////////////////////////////
  143. // CHHFinder
  144. HRESULT STDMETHODCALLTYPE CHHFinder::FindThisFile(const WCHAR* pwszFileName,
  145. WCHAR** ppwszPathName, BOOL* pfRecordPathInRegistry )
  146. {
  147. CExCollection* pCollection;
  148. CExTitle* pTitle = NULL;
  149. PCSTR pszPathName = NULL;
  150. CStr PathName;
  151. HRESULT hr = S_OK;
  152. // guarantee that we never record this value in the registry since it can always change.
  153. *pfRecordPathInRegistry = FALSE;
  154. CHAR pszFileName[MAX_PATH];
  155. WideCharToMultiByte(CP_ACP, 0, pwszFileName, -1, pszFileName, MAX_PATH, NULL, NULL);
  156. // get a pointer to the title and use this to get the fullpathname
  157. pCollection = GetCurrentCollection(NULL, pszFileName);
  158. if( pCollection )
  159. hr = pCollection->URL2ExTitle( pszFileName, &pTitle );
  160. #if 0
  161. // if this is not a collection or we could not find the title then give
  162. // the ::FindThisFile function a try (since we know removable media
  163. // is not supported for non-collections anyway)
  164. if( !pCollection || !pTitle ) {
  165. // check the directory where the master file of the current collection lives
  166. CExCollection* pCurCollection = NULL;
  167. if( g_pCurrentCollection )
  168. pCurCollection = g_pCurrentCollection;
  169. else if( g_phmData && g_phmData[0] )
  170. pCurCollection = g_phmData[0]->m_pTitleCollection;
  171. if( pCurCollection ) {
  172. CHAR szPathName[_MAX_PATH];
  173. CHAR szFileName[_MAX_FNAME];
  174. CHAR szExtension[_MAX_EXT];
  175. SplitPath((PSTR)pszFileName, NULL, NULL, szFileName, szExtension);
  176. CHAR szMasterPath[_MAX_PATH];
  177. CHAR szMasterDrive[_MAX_DRIVE];
  178. SplitPath((PSTR)pCurCollection->m_csFile, szMasterDrive, szMasterPath, NULL, NULL);
  179. strcpy( szPathName, szMasterDrive );
  180. CatPath( szPathName, szMasterPath );
  181. CatPath( szPathName, szFileName );
  182. strcat( szPathName, szExtension );
  183. if( (GetFileAttributes(szPathName) != HFILE_ERROR) ) {
  184. PathName = szPathName;
  185. pszPathName = PathName.psz;
  186. }
  187. }
  188. if( !pszPathName ) {
  189. if( ::FindThisFile( NULL, pszFileName, &PathName, FALSE ) ) {
  190. pszPathName = PathName.psz;
  191. }
  192. else {
  193. #ifdef _DEBUG
  194. CHAR szMsg[1024];
  195. wsprintf( szMsg, "HHFinder Debug Message\n\nCould not locate the file \"%s\".", pszFileName );
  196. MsgBox( szMsg, MB_OK );
  197. #endif
  198. return S_OK;
  199. }
  200. }
  201. }
  202. #endif
  203. // Removable media support (Refresh bypasses BeforeNavigate so we need this here).
  204. //
  205. // Note, this must be one of the first things we do since the user can
  206. // change the title's location
  207. //
  208. if( pTitle ) {
  209. pszPathName = pTitle->GetPathName();
  210. if( FAILED(hr = EnsureStorageAvailability( pTitle )) ) {
  211. return S_OK;
  212. }
  213. }
  214. // if we made it here than this mean we found it (if is does exist)
  215. // and pszPathName points to the full pathname
  216. LPMALLOC pMalloc;
  217. WCHAR pwszPathName[MAX_PATH];
  218. *ppwszPathName = NULL;
  219. if( pszPathName && *pszPathName ) {
  220. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, pwszPathName, MAX_PATH);
  221. // allocate and copy the pathname
  222. if( SUCCEEDED(hr = CoGetMalloc(1, &pMalloc)) ) {
  223. *ppwszPathName = (WCHAR*) pMalloc->Alloc( (wcslen(pwszPathName)+1)*sizeof(WCHAR) );
  224. if( !*ppwszPathName ) {
  225. hr = E_OUTOFMEMORY;
  226. }
  227. else {
  228. wcscpy( *ppwszPathName, pwszPathName );
  229. hr = S_OK;
  230. }
  231. pMalloc->Release();
  232. }
  233. }
  234. if (*ppwszPathName == NULL)
  235. hr = STG_E_FILENOTFOUND;
  236. return hr;
  237. }
  238. /////////////////////////////////////////////////////////////////////////////
  239. // EnsureStorageAvailability
  240. // Code to detect and handle Advanced Media Support issues (formerly RMS issues)
  241. //
  242. // Types are:
  243. //
  244. // HHRMS_TYPE_TITLE (default)
  245. // HHRMS_TYPE_COMBINED_QUERY
  246. // HHRMS_TYPE_ATTACHMENT // a.k.a Sample
  247. //
  248. // return values are as follows:
  249. // S_OK - The storage is available (party on!)
  250. // HHRMS_S_LOCATION_UPDATE - The user changed the location of the volume
  251. // E_FAIL - The storage is unknown (caller should handle this failure condition)
  252. // HHRMS_E_SKIP - User choose to skip this volume just this time
  253. // HHRMS_E_SKIP_ALWAYS - User choose to skip this volume for this entire session
  254. //
  255. // For URL navigation, we should always volume check and always prompt.
  256. //
  257. // For Queries, we should volume check for chm files and not volume check for chq files
  258. // and we will always prompt for the volume for this session unless the user
  259. // selects cancel.
  260. //
  261. HRESULT EnsureStorageAvailability( CExTitle* pTitle, UINT uiFileType,
  262. BOOL bVolumeCheckIn, BOOL bAlwaysPrompt,
  263. BOOL bNeverPrompt )
  264. {
  265. HRESULT hr = S_OK;
  266. // if we do not have a title pointer this indicates that the URL does not belong to a
  267. // compressed title and thus we should claim the storage is available and let IE decide
  268. // what to do with it
  269. if( !pTitle )
  270. return S_OK;
  271. BOOL bVolumeCheck = bVolumeCheckIn;
  272. // Get the location information
  273. LOCATIONHISTORY* pLocationHistory = pTitle->GetUsedLocation();
  274. // Get the collection
  275. CExCollection* pCollection = pTitle->m_pCollection;
  276. // Only check removable media when running in a collection
  277. //
  278. if(pCollection && pCollection->IsSingleTitle())
  279. return S_OK;
  280. // Get the location identifier
  281. CHAR szLocationId[MAX_PATH];
  282. CLocation* pLocation = NULL;
  283. if( pLocationHistory ) {
  284. switch( uiFileType ) {
  285. case HHRMS_TYPE_TITLE:
  286. strcpy( szLocationId, pLocationHistory->LocationId );
  287. break;
  288. case HHRMS_TYPE_COMBINED_QUERY:
  289. if( pLocationHistory->QueryLocation && pLocationHistory->QueryLocation[0] )
  290. strcpy( szLocationId, pLocationHistory->QueryLocation );
  291. else if( pLocationHistory->LocationId && pLocationHistory->LocationId[0] )
  292. strcpy( szLocationId, pLocationHistory->LocationId );
  293. break;
  294. case HHRMS_TYPE_ATTACHMENT:
  295. if( pLocationHistory->SampleLocation && pLocationHistory->SampleLocation[0] )
  296. strcpy( szLocationId, pLocationHistory->SampleLocation );
  297. else if( pLocationHistory->LocationId && pLocationHistory->LocationId[0] )
  298. strcpy( szLocationId, pLocationHistory->LocationId );
  299. break;
  300. default:
  301. strcpy( szLocationId, pLocationHistory->LocationId );
  302. break;
  303. }
  304. pLocation = pCollection->m_Collection.FindLocation( szLocationId );
  305. }
  306. // if we have location information then get the details about it
  307. // otherwise never prompt or volume check (check existence only).
  308. PCSTR pszVolumeLabel = NULL;
  309. PCSTR pszVolumeName = NULL;
  310. if( pLocation ) {
  311. pszVolumeLabel = pLocation->GetVolume(); // Get the volume label
  312. pszVolumeName = pLocation->GetTitle(); // Get volume's friendly name
  313. }
  314. else {
  315. bVolumeCheck = FALSE;
  316. bNeverPrompt = TRUE;
  317. }
  318. // Get the pathname
  319. PCSTR pszPathname = NULL;
  320. switch( uiFileType ) {
  321. case HHRMS_TYPE_TITLE:
  322. pszPathname = pTitle->GetPathName();
  323. break;
  324. case HHRMS_TYPE_COMBINED_QUERY:
  325. pszPathname = pTitle->GetQueryName();
  326. break;
  327. case HHRMS_TYPE_ATTACHMENT:
  328. pszPathname = pTitle->GetCurrentAttachmentName();
  329. break;
  330. default:
  331. return E_FAIL;
  332. break;
  333. }
  334. // Get the location path and filename
  335. CHAR szPath[MAX_PATH];
  336. CHAR szFilename[MAX_PATH];
  337. PCSTR pszPath = szPath;
  338. szPath[0]= 0;
  339. szFilename[0]= 0;
  340. if( pLocation ) {
  341. strcpy( szPath, pLocation->GetPath() );
  342. CHAR szExt[MAX_PATH];
  343. CHAR szTmpPath[MAX_PATH];
  344. CHAR szDrive[MAX_PATH];
  345. CHAR szDir[MAX_PATH];
  346. szTmpPath[0] = 0;
  347. SplitPath( pszPathname, szDrive, szDir, szFilename, szExt );
  348. strcat( szFilename, szExt );
  349. // make sure that the filename includes and subdirs not part of the path
  350. //
  351. // for example the path may be e:\samples but the pathname is c:\samples\sfl\samp.sfl
  352. // and thus the path is e:\samples but the filename should be sfl\samp.sfl and not
  353. // just samp.sfl
  354. if( szDrive[0] )
  355. strcpy( szTmpPath, szDrive );
  356. if( szDir )
  357. strcat( szTmpPath, szDir );
  358. // STang:
  359. // Buggy, must make sure pszPath is a prefix of szTmpPath ( except the drive letter )
  360. // if( strlen( szTmpPath ) != strlen( pszPath ) )
  361. if( strnicmp(pszPath+1,szTmpPath+1,(int)strlen(pszPath)-1) == 0 && strlen( szTmpPath ) > strlen( pszPath ) )
  362. {
  363. CHAR sz[MAX_PATH];
  364. strcpy( sz, &szTmpPath[strlen(pszPath)] );
  365. strcat( sz, szFilename );
  366. strcpy( szFilename, sz );
  367. }
  368. }
  369. else
  370. GetPathAndFileName( pszPathname, szPath, szFilename );
  371. // make sure to disable the default error message the OS displays
  372. // when doing a file check on removable media
  373. UINT uiErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
  374. // get the drive of the path
  375. CHAR szDriveRoot[4];
  376. lstrcpyn( szDriveRoot, szPath, 4 );
  377. #define mkupper(c) ((c)-'a'+'A')
  378. if( szDriveRoot[0] >= 'a' )
  379. szDriveRoot[0] = mkupper(szDriveRoot[0]); // make it upper case
  380. // Make copies of various settings to support location updating
  381. CHAR szVolumeLabelTry[MAX_PATH];
  382. CHAR szPathTry[MAX_PATH];
  383. CHAR szPathnameTry[MAX_PATH];
  384. CHAR szDriveRootTry[4];
  385. // setup the paths to try
  386. strcpy( szPathTry, szPath );
  387. strcpy( szPathnameTry, pszPathname );
  388. strcpy( szDriveRootTry, szDriveRoot );
  389. if( bVolumeCheck ) { //HH Bug 2521: Make sure pszVolumeLabel is non-null before copy.
  390. ASSERT( pszVolumeLabel );
  391. strcpy( szVolumeLabelTry, pszVolumeLabel );
  392. }
  393. else {
  394. strcpy( szVolumeLabelTry, "" );
  395. }
  396. // Setup prompting loop starting conditions
  397. BOOL bExistenceCheck = TRUE;
  398. BOOL bPrompt = FALSE;
  399. // === MAIN PROMPTING LOOP BEGINS HERE === //
  400. while( TRUE ) {
  401. // make sure to add a backslash if the second CHAR is a colon
  402. // sometimes we will get just "d:" instead of "d:\" and thus
  403. // GetDriveType will fail under this circumstance
  404. if( szDriveRootTry[1] == ':' ) {
  405. szDriveRootTry[2] = '\\';
  406. szDriveRootTry[3] = 0;
  407. }
  408. // Get media type
  409. UINT uiDriveType = DRIVE_UNKNOWN;
  410. if( szDriveRootTry[1] == ':' && szDriveRootTry[2] == '\\' ) {
  411. uiDriveType = GetDriveType(szDriveRootTry);
  412. }
  413. else if( szDriveRootTry[0] == '\\' && szDriveRootTry[1] == '\\' ) {
  414. uiDriveType = DRIVE_REMOTE;
  415. bVolumeCheck = FALSE; // never check volume label of network drives
  416. }
  417. // Determine and handle the drive types
  418. bExistenceCheck = TRUE;
  419. switch( uiDriveType ) {
  420. case DRIVE_FIXED:
  421. case DRIVE_RAMDISK:
  422. uiDriveType = DRIVE_FIXED;
  423. // fall thru
  424. case DRIVE_REMOTE:
  425. bVolumeCheck = FALSE;
  426. break;
  427. case DRIVE_REMOVABLE:
  428. case DRIVE_CDROM:
  429. case DRIVE_UNKNOWN:
  430. case DRIVE_NO_ROOT_DIR:
  431. if( bVolumeCheckIn )
  432. bVolumeCheck = TRUE;
  433. break;
  434. default: // unknown types
  435. bVolumeCheck = FALSE;
  436. bExistenceCheck = FALSE;
  437. break;
  438. }
  439. // Prompt for media
  440. if( bPrompt ) {
  441. CHAR szDriveLetter[4];
  442. szDriveLetter[0] = szDriveRoot[0];
  443. szDriveLetter[1] = szDriveRoot[1];
  444. szDriveLetter[2] = 0;
  445. HHREMOVABLE Removable;
  446. Removable.uiDriveType = uiDriveType;
  447. Removable.pszDriveLetter = szDriveLetter;
  448. Removable.pszVolumeName = pszVolumeName;
  449. PSTR pszPathTry = szPathTry;
  450. Removable.ppszLocation = &pszPathTry;
  451. HCURSOR hCursor = GetCursor();
  452. // Disable all of the toplevel application windows, before we bring up the dialog.
  453. CLockOut LockOut ;
  454. LockOut.LockOut(GetActiveWindow()) ;
  455. // Display the dialog box.
  456. INT_PTR iReturn = DialogBoxParam( _Module.GetResourceInstance(),
  457. MAKEINTRESOURCE(IDD_REMOVEABLE_MEDIA_PROMPT),
  458. GetActiveWindow(), RemovableMediaDialogProc,
  459. (LPARAM) &Removable );
  460. // Enable all of the windows which we disabled.
  461. LockOut.Unlock() ;
  462. SetCursor( hCursor );
  463. if( iReturn == IDOK ) {
  464. strcpy( szPathnameTry, pszPathTry );
  465. CatPath( szPathnameTry, szFilename );
  466. lstrcpyn( szDriveRootTry, pszPathTry, 4 );
  467. bPrompt = FALSE;
  468. continue;
  469. }
  470. else if( iReturn == IDCANCEL ) {
  471. if( !bAlwaysPrompt )
  472. g_LocationSkipList.Add( szLocationId );
  473. hr = HHRMS_E_SKIP;
  474. break;
  475. }
  476. }
  477. // Validate media is present using the volume label, if needed
  478. if( bVolumeCheck ) {
  479. CHAR szVolume[MAX_PATH];
  480. szVolume[0] = 0;
  481. CHAR szFileSystemName[MAX_PATH];
  482. DWORD dwMaximumComponentLength = 0;
  483. DWORD dwFileSystemFlags = 0;
  484. BOOL bReturn = GetVolumeInformation( szDriveRootTry, szVolume, sizeof(szVolume),
  485. NULL, &dwMaximumComponentLength, &dwFileSystemFlags, szFileSystemName, sizeof(szFileSystemName) );
  486. if( bVolumeCheckIn && (!bReturn || (strcmp( szVolume, szVolumeLabelTry ) != 0)) )
  487. bExistenceCheck = FALSE;
  488. }
  489. // if the file exists, and it matches the chi file (for title checks only) the we have the right media
  490. if( bExistenceCheck && IsFile( szPathnameTry ) && ((uiFileType==HHRMS_TYPE_TITLE)?pTitle->EnsureChmChiMatch( szPathnameTry ):TRUE ) ) {
  491. hr = S_OK;
  492. // TODO: the version of MSDN that shipped with VS 6.0 is broken for net installs.
  493. // For a network install, they erroneously set the volume label for CD2, also
  494. // known as "98VS-1033-CD2", to "DN600ENU1" instead of "DN600ENU2". To fix this we
  495. // need to ignore the language settings of "1033" or "ENU" and make the appropriate
  496. // change to the volume label. We must do this before we call UpdateLocation since
  497. // it could change the location information for CD1 when the user updates the CD2
  498. // location information.
  499. // Never change the volume label unless the new destination is
  500. // removable media!
  501. //
  502. // Setup should adhere to the following rules:
  503. //
  504. // 1. Each local disk and network destination path must use a
  505. // volume name unique for each set of titles from each CD source
  506. // and they must be unique from the CD source volume label.
  507. // It is advised that these volume names be the volume label name
  508. // of the removable media (sahipped media) that the group came
  509. // from appended with the destination type name and number such as
  510. // "-LocalX" or "-NetX".
  511. // 2. Volume names for CD "destinations" must be identical to the
  512. // CD's volume name.
  513. // 3. Note, locations with the same volume name will automatically
  514. // get their path updated when any one of them changes.
  515. //
  516. // if the path did change then update the information, otherwise were done
  517. if( lstrcmpi( szPathTry, szPath ) != 0 ) {
  518. // STang
  519. char * pcVolume = NULL;
  520. if ( ( (uiDriveType == DRIVE_REMOVABLE) || (uiDriveType == DRIVE_CDROM) )
  521. && bVolumeCheck )
  522. pcVolume = szVolumeLabelTry;
  523. pCollection->UpdateLocation( (PSTR) szLocationId, szPathTry, pcVolume );
  524. // pCollection->UpdateLocation( (PSTR) szLocationId, szPathTry,
  525. // ( (uiDriveType == DRIVE_REMOVABLE) || (uiDriveType == DRIVE_CDROM)) ? szVolumeLabelTry : NULL );
  526. hr = HHRMS_S_LOCATION_UPDATE;
  527. }
  528. break;
  529. }
  530. // Bail out if we never want to prompt for media
  531. if( bNeverPrompt ) {
  532. #ifdef _DEBUG
  533. if( g_bShowMessage && (uiFileType != HHRMS_TYPE_COMBINED_QUERY) ) {
  534. CHAR szMsg[1024];
  535. wsprintf( szMsg, "HHFinder Debug Message\n\n"
  536. "Could not find the file:\n \"%s\"\n"
  537. "at the location specified.", szPathnameTry );
  538. if( pTitle && pTitle->m_pTitle ) {
  539. CHAR szMsg2[1024];
  540. wsprintf( szMsg2, "\n\nTitle ID: \"%s\".", pTitle->m_pTitle->GetId() );
  541. strcat( szMsg, szMsg2 );
  542. }
  543. strcat( szMsg, "\n\nPress 'OK' to continue or 'Cancel' to disable this warning.");
  544. int iReturn = MsgBox( szMsg, MB_OKCANCEL );
  545. if( iReturn == IDCANCEL )
  546. g_bShowMessage = FALSE;
  547. }
  548. #endif
  549. // if existence check was desired then this is a failure condition
  550. if( bExistenceCheck ) {
  551. hr = E_FAIL;
  552. break;
  553. }
  554. // Bailout and let the caller know we are skipping this one
  555. hr = HHRMS_E_SKIP;
  556. break;
  557. }
  558. // If we do not require that we always prompt, check the volume against
  559. // our skip list
  560. if( !bAlwaysPrompt ) {
  561. if( !bNeverPrompt )
  562. if( g_LocationSkipList.Find( szLocationId ) ) {
  563. hr = HHRMS_E_SKIP_ALWAYS;
  564. break;
  565. }
  566. }
  567. #ifdef _DEBUG
  568. // Let the user know that we could not find the title at the location specified
  569. if( bPrompt ) {
  570. CHAR szMsg[1024];
  571. wsprintf( szMsg, "HHFinder Debug Message\n\n"
  572. "Could not find the file:\n \"%s\"\n"
  573. "at the location specified.", szFilename );
  574. if( pTitle && pTitle->m_pTitle ) {
  575. CHAR szMsg2[1024];
  576. wsprintf( szMsg2, "\n\nTitle ID: \"%s\".", pTitle->m_pTitle->GetId() );
  577. strcat( szMsg, szMsg2 );
  578. }
  579. MsgBox( szMsg, MB_OKCANCEL );
  580. }
  581. #endif
  582. // restore the original path information, and continue
  583. strcpy( szPathTry, szPath );
  584. strcpy( szPathnameTry, pszPathname );
  585. strcpy( szDriveRootTry, szDriveRoot );
  586. if( bVolumeCheck ) { //HH Bug 2521: Make sure pszVolumeLabel is non-null before copy.
  587. ASSERT( pszVolumeLabel );
  588. strcpy( szVolumeLabelTry, pszVolumeLabel );
  589. }
  590. else {
  591. strcpy( szVolumeLabelTry, "" );
  592. }
  593. bPrompt = TRUE;
  594. }
  595. // === MAIN PROMPTING LOOP ENDS HERE === //
  596. // restore the previous error mode
  597. SetErrorMode( uiErrorMode );
  598. return hr;
  599. }
  600. /////////////////////////////////////////////////////////////////////////////
  601. // CD Swap Dialog
  602. INT_PTR CALLBACK RemovableMediaDialogProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  603. {
  604. static HHREMOVABLE* pRemovable = NULL;
  605. static HWND hWndIcon = NULL;
  606. switch( uMsg ) {
  607. case WM_INITDIALOG: {
  608. pRemovable = (HHREMOVABLE*) lParam;
  609. // get and set our dialog title title
  610. PCSTR pszTitle = GetStringResource( IDS_MSGBOX_TITLE );
  611. SetWindowText( hDlg, pszTitle );
  612. //get media name and icon
  613. PCSTR pszMediaName = NULL;
  614. PCSTR pszIcon = NULL;
  615. DWORD dwFormatMessage = 0;
  616. if( pRemovable->uiDriveType == DRIVE_REMOVABLE ) {
  617. pszIcon = "IconDisk350";
  618. pszMediaName = GetStringResource( IDS_REMOVABLE_MEDIA_DISK ); // "disk"
  619. dwFormatMessage = IDS_REMOVABLE_MEDIA_MESSAGE_FORMAT;
  620. }
  621. #ifdef HH_VERSION_1_3
  622. else if( pRemovable->uiDriveType == DRIVE_REMOTE ) {
  623. pszIcon = "IconRemote";
  624. pszMediaName = GetStringResource( IDS_REMOVABLE_MEDIA_REMOTE ); // "Network location"
  625. dwFormatMessage = IDS_REMOVABLE_MEDIA_MESSAGE_FORMAT2;
  626. }
  627. else if( pRemovable->uiDriveType == DRIVE_FIXED ) {
  628. pszIcon = "IconFixed";
  629. pszMediaName = GetStringResource( IDS_REMOVABLE_MEDIA_FIXED ); // "local disk"
  630. dwFormatMessage = IDS_REMOVABLE_MEDIA_MESSAGE_FORMAT2;
  631. }
  632. #endif
  633. else /* if( pRemovable->uiDriveType == DRIVE_CDROM ) */ {
  634. pszIcon = "IconCDROM";
  635. pszMediaName = GetStringResource( IDS_REMOVABLE_MEDIA_CDROM ); // "CD-ROM disc"
  636. dwFormatMessage = IDS_REMOVABLE_MEDIA_MESSAGE_FORMAT;
  637. }
  638. CHAR szMediaName[64];
  639. strcpy( szMediaName, pszMediaName );
  640. // set the icon
  641. hWndIcon = CreateWindow( TEXT( "static" ), pszIcon,
  642. WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SS_ICON,
  643. 15, 15, 0, 0, hDlg, NULL, _Module.GetModuleInstance(), NULL );
  644. // get location message format string
  645. PCSTR pszFormat = GetStringResource( dwFormatMessage );
  646. CHAR szFormat[256];
  647. strcpy( szFormat, pszFormat );
  648. // format the location message
  649. DWORD dwArgCount = 3;
  650. #ifdef HH_VERSION_1_3
  651. if( dwFormatMessage == IDS_REMOVABLE_MEDIA_MESSAGE_FORMAT2 )
  652. dwArgCount = 2;
  653. #endif
  654. DWORD_PTR* pArg = new DWORD_PTR[dwArgCount];
  655. pArg[0] = (DWORD_PTR) szMediaName;
  656. pArg[1] = (DWORD_PTR) pRemovable->pszVolumeName;
  657. if( dwArgCount == 3 )
  658. pArg[2] = (DWORD_PTR) pRemovable->pszDriveLetter;
  659. CHAR szMessage[1024];
  660. FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  661. szFormat, 0, 0, szMessage, sizeof(szMessage), (va_list*) pArg );
  662. delete [] pArg;
  663. // set the location message
  664. #ifdef HH_VERSION_1_3
  665. ::SendMessage(GetDlgItem( hDlg, IDC_LOCATION_NAME ), WM_SETFONT, (WPARAM) _Resource.GetUIFont(), FALSE);
  666. #else
  667. ::SendMessage(GetDlgItem( hDlg, IDC_LOCATION_NAME ), WM_SETFONT, (WPARAM) _Resource.DefaultFont(), FALSE);
  668. #endif
  669. SetWindowText( GetDlgItem( hDlg, IDC_LOCATION_NAME ), szMessage );
  670. // set the location path
  671. #ifdef HH_VERSION_1_3
  672. ::SendMessage(GetDlgItem( hDlg, IDC_LOCATION_PATH ), WM_SETFONT, (WPARAM) _Resource.GetUIFont(), FALSE);
  673. #else
  674. ::SendMessage(GetDlgItem( hDlg, IDC_LOCATION_PATH ), WM_SETFONT, (WPARAM) _Resource.DefaultFont(), FALSE);
  675. #endif
  676. SetWindowText( GetDlgItem( hDlg, IDC_LOCATION_PATH ), *(pRemovable->ppszLocation) );
  677. // disable the location path for now
  678. //EnableWindow( GetDlgItem( hDlg, IDC_LOCATION_PATH ), FALSE );
  679. // center the dialog
  680. CenterWindow( GetParent( hDlg ), hDlg );
  681. return TRUE;
  682. }
  683. case WM_COMMAND:
  684. if( LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL ) {
  685. // return the path
  686. GetWindowText( GetDlgItem( hDlg, IDC_LOCATION_PATH ), (PSTR) *(pRemovable->ppszLocation), MAX_PATH );
  687. // make sure the returned path includes a trailing backslash
  688. PSTR* ppsz = pRemovable->ppszLocation;
  689. int iLen = (int)strlen(*ppsz);
  690. if( (*ppsz)[iLen-1] != '\\' ) {
  691. (*ppsz)[iLen] = '\\';
  692. (*ppsz)[iLen+1] = 0;
  693. }
  694. DestroyWindow( hWndIcon );
  695. pRemovable = NULL;
  696. hWndIcon = NULL;
  697. EndDialog( hDlg, LOWORD( wParam ) );
  698. }
  699. else if( LOWORD(wParam) == ID_BROWSE ) {
  700. CStr strPath;
  701. if( DlgOpenDirectory( hDlg, &strPath ) ) {
  702. SetWindowText( GetDlgItem( hDlg, IDC_LOCATION_PATH ), strPath.psz );
  703. }
  704. }
  705. break;
  706. }
  707. return FALSE;
  708. }