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.

1567 lines
44 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: getinfo.cpp
  3. *
  4. * Author: David Stewart [dstewart]
  5. *
  6. * Copyright (c) 1998 Microsoft Corporation. All rights reserved.
  7. \**************************************************************************/
  8. #include <TCHAR.H>
  9. #include <objbase.h>
  10. #include <mmsystem.h> //for mci commands
  11. #include <urlmon.h>
  12. #include <hlguids.h> //for IID_IBindStatusCallback
  13. #include "getinfo.h"
  14. #include "netres.h"
  15. #include "wininet.h"
  16. #include "condlg.h"
  17. #include "..\main\mmfw.h"
  18. #include "..\cdopt\cdopt.h"
  19. #include "mapi.h"
  20. #include <stdio.h>
  21. extern HINSTANCE g_dllInst;
  22. #define MODE_OK 0
  23. #define MODE_MULTIPLE 1
  24. #define MODE_NOT_FOUND 2
  25. #define FRAMES_PER_SECOND 75
  26. #define FRAMES_PER_MINUTE (60*FRAMES_PER_SECOND)
  27. #define MAX_UPLOAD_URL_LENGTH 1500
  28. #ifdef UNICODE
  29. #define URLFUNCTION "URLOpenStreamW"
  30. #define CANONFUNCTION "InternetCanonicalizeUrlW"
  31. #else
  32. #define URLFUNCTION "URLOpenStreamA"
  33. #define CANONFUNCTION "InternetCanonicalizeUrlA"
  34. #endif
  35. HWND g_hwndParent = NULL;
  36. extern HINSTANCE g_hURLMon;
  37. LPCDOPT g_pNetOpt = NULL;
  38. LPCDDATA g_pNetData = NULL;
  39. BOOL g_fCancelDownload = FALSE; //ANY ACCESS MUST BE SURROUNDED by Enter/Leave g_Critical
  40. IBinding* g_pBind = NULL; //ANY ACCESS MUST BE SURROUNDED by Enter/Leave g_Critical
  41. long g_lNumDownloadingThreads = 0; //MUST USE InterlockedIncrement/Decrement
  42. BOOL g_fDownloadDone = FALSE;
  43. BOOL g_fDBWriteFailure = FALSE;
  44. extern CRITICAL_SECTION g_Critical;
  45. extern CRITICAL_SECTION g_BatchCrit;
  46. DWORD WINAPI SpawnSingleDownload(LPVOID pParam);
  47. DWORD WINAPI SpawnBatchDownload(LPVOID pParam);
  48. DWORD WINAPI DoBatchDownload(LPCDBATCH pBatchList, HWND hwndParent);
  49. BOOL DoDownload(TCHAR* url, TCHAR* szFilename, HWND hwndParent);
  50. CCDNet::CCDNet()
  51. {
  52. m_dwRef = 0;
  53. }
  54. CCDNet::~CCDNet()
  55. {
  56. }
  57. STDMETHODIMP CCDNet::QueryInterface(REFIID riid, void** ppv)
  58. {
  59. *ppv = NULL;
  60. if (IID_IUnknown == riid || IID_ICDNet == riid)
  61. {
  62. *ppv = this;
  63. }
  64. if (NULL==*ppv)
  65. {
  66. return E_NOINTERFACE;
  67. }
  68. AddRef();
  69. return S_OK;
  70. }
  71. STDMETHODIMP_(ULONG) CCDNet::AddRef(void)
  72. {
  73. return ++m_dwRef;
  74. }
  75. STDMETHODIMP_(ULONG) CCDNet::Release(void)
  76. {
  77. if (0!=--m_dwRef)
  78. return m_dwRef;
  79. delete this;
  80. return 0;
  81. }
  82. STDMETHODIMP CCDNet::SetOptionsAndData(void* pOpts, void* pData)
  83. {
  84. g_pNetOpt = (LPCDOPT)pOpts;
  85. g_pNetData = (LPCDDATA)pData;
  86. return S_OK;
  87. }
  88. //this is a start to implementing the "upload via http" case rather than the
  89. //upload via mail case
  90. BOOL UploadToProvider(LPCDPROVIDER pProvider, LPCDTITLE pTitle, HWND hwndParent)
  91. {
  92. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  93. TCHAR szMainURL[INTERNET_MAX_URL_LENGTH];
  94. TCHAR szFilename[MAX_PATH];
  95. //get the InternetCanonicalizeURL function
  96. typedef BOOL (PASCAL *CANPROC)(LPCTSTR, LPTSTR, LPDWORD, DWORD);
  97. CANPROC canProc = NULL;
  98. HMODULE hNet = LoadLibrary(TEXT("WININET.DLL"));
  99. if (hNet!=NULL)
  100. {
  101. canProc = (CANPROC)GetProcAddress(hNet,CANONFUNCTION);
  102. }
  103. else
  104. {
  105. return FALSE;
  106. }
  107. if (pProvider && pTitle && canProc)
  108. {
  109. //check for provider URL
  110. if (_tcslen(pProvider->szProviderUpload)>0)
  111. {
  112. TCHAR szTempCan[MAX_PATH*2];
  113. //create the URL to send
  114. wsprintf(szMainURL,TEXT("%s%s"),pProvider->szProviderUpload,pTitle->szTitleQuery);
  115. _tcscpy(szURL,szMainURL);
  116. //add title
  117. _tcscat(szURL,TEXT("&t="));
  118. DWORD dwSize = sizeof(szTempCan);
  119. canProc(pTitle->szTitle,szTempCan,&dwSize,0);
  120. _tcscat(szURL,szTempCan);
  121. //add artist
  122. _tcscat(szURL,TEXT("&a="));
  123. dwSize = sizeof(szTempCan);
  124. canProc(pTitle->szArtist,szTempCan,&dwSize,0);
  125. _tcscat(szURL,szTempCan);
  126. //add tracks
  127. TCHAR szTrack[MAX_PATH];
  128. for (DWORD i = 0; i < pTitle->dwNumTracks; i++)
  129. {
  130. wsprintf(szTrack,TEXT("&%u="),i+1);
  131. dwSize = sizeof(szTempCan);
  132. canProc(pTitle->pTrackTable[i].szName,szTempCan,&dwSize,0);
  133. if ((_tcslen(szURL) + _tcslen(szTrack) + _tcslen(szTempCan)) >
  134. MAX_UPLOAD_URL_LENGTH-sizeof(TCHAR))
  135. {
  136. //we're coming close to the limit. Send what we have and start rebuilding
  137. if (!g_fCancelDownload)
  138. {
  139. if (DoDownload(szURL,szFilename, hwndParent))
  140. {
  141. DeleteFile(szFilename);
  142. } //end if "upload" successful
  143. else
  144. {
  145. //bad upload, don't bother sending the rest
  146. //probably a timeout
  147. return FALSE;
  148. }
  149. }
  150. //reset the URL to just the provider + toc
  151. _tcscpy(szURL,szMainURL);
  152. } //end if length
  153. _tcscat(szURL,szTrack);
  154. _tcscat(szURL,szTempCan);
  155. } //end for track
  156. //send it
  157. if (!g_fCancelDownload)
  158. {
  159. if (DoDownload(szURL,szFilename, hwndParent))
  160. {
  161. DeleteFile(szFilename);
  162. } //end if "upload" successful
  163. else
  164. {
  165. return FALSE;
  166. }
  167. }
  168. } //end if url exists
  169. } //end if state OK
  170. if (hNet)
  171. {
  172. FreeLibrary(hNet);
  173. }
  174. return TRUE;
  175. }
  176. DWORD WINAPI UploadThread(LPVOID pParam)
  177. {
  178. InterlockedIncrement((LONG*)&g_lNumDownloadingThreads);
  179. //this will block us against the batch download happening, too
  180. EnterCriticalSection(&g_BatchCrit);
  181. LPCDTITLE pTitle = (LPCDTITLE)pParam;
  182. HWND hwndParent = g_hwndParent;
  183. int nTries = 0;
  184. int nSuccessful = 0;
  185. if (pTitle)
  186. {
  187. LPCDOPTIONS pOptions = g_pNetOpt->GetCDOpts(); // Get the options, needed for provider list
  188. if (pOptions && pOptions->pCurrentProvider) // Make sure we have providers
  189. {
  190. LPCDPROVIDER pProviderList = NULL;
  191. LPCDPROVIDER pProvider = NULL;
  192. g_pNetOpt->CreateProviderList(&pProviderList); // Get the sorted provider list
  193. pProvider = pProviderList; // Get the head of the list
  194. while ((pProvider) && (!g_fCancelDownload))
  195. {
  196. nTries++;
  197. if (UploadToProvider(pProvider,pTitle,hwndParent))
  198. {
  199. nSuccessful++;
  200. }
  201. pProvider = pProvider->pNext;
  202. }
  203. g_pNetOpt->DestroyProviderList(&pProviderList);
  204. } //end if providers
  205. }
  206. //addref'ed before thread was created
  207. g_pNetOpt->Release();
  208. g_pNetData->Release();
  209. long status = UPLOAD_STATUS_NO_PROVIDERS;
  210. if ((nSuccessful != nTries) && (nSuccessful > 0))
  211. {
  212. status = UPLOAD_STATUS_SOME_PROVIDERS;
  213. }
  214. if ((nSuccessful == nTries) && (nSuccessful > 0))
  215. {
  216. status = UPLOAD_STATUS_ALL_PROVIDERS;
  217. }
  218. if (g_fCancelDownload)
  219. {
  220. status = UPLOAD_STATUS_CANCELED;
  221. }
  222. LeaveCriticalSection(&g_BatchCrit);
  223. InterlockedDecrement((LONG*)&g_lNumDownloadingThreads);
  224. //post message saying we're done
  225. PostMessage(hwndParent,WM_NET_DONE,(WPARAM)g_dllInst,status);
  226. return 0;
  227. }
  228. STDMETHODIMP CCDNet::Upload(LPCDTITLE pTitle, HWND hwndParent)
  229. {
  230. HRESULT hr = E_FAIL;
  231. DWORD dwHow;
  232. BOOL fConnected;
  233. if (g_pNetOpt && g_pNetData && pTitle) // Make sure we are in a valid state
  234. {
  235. fConnected = _InternetGetConnectedState(&dwHow,0,TRUE); // Make sure we are connected to net
  236. if (fConnected) // Make sure we are in a valid state
  237. {
  238. EnterCriticalSection(&g_Critical);
  239. g_fCancelDownload = FALSE;
  240. LeaveCriticalSection(&g_Critical);
  241. DWORD dwThreadID;
  242. HANDLE hNetThread = NULL;
  243. g_hwndParent = hwndParent;
  244. g_pNetOpt->AddRef();
  245. g_pNetData->AddRef();
  246. hNetThread = CreateThread(NULL,0,UploadThread,(void*)pTitle,0,&dwThreadID);
  247. if (hNetThread)
  248. {
  249. CloseHandle(hNetThread);
  250. hr = S_OK;
  251. }
  252. } //end if connected
  253. } //end if options and data ok
  254. return (hr);
  255. }
  256. STDMETHODIMP_(BOOL) CCDNet::CanUpload()
  257. {
  258. BOOL retcode = FALSE;
  259. if (g_pNetOpt && g_pNetData) // Make sure we are in a valid state
  260. {
  261. //check all providers to be sure at least one has upload capability
  262. LPCDOPTIONS pOptions = g_pNetOpt->GetCDOpts(); // Get the options, needed for provider list
  263. if (pOptions && pOptions->pCurrentProvider) // Make sure we have providers
  264. {
  265. LPCDPROVIDER pProviderList = NULL;
  266. LPCDPROVIDER pProvider = NULL;
  267. g_pNetOpt->CreateProviderList(&pProviderList); // Get the sorted provider list
  268. pProvider = pProviderList; // Get the head of the list
  269. while (pProvider)
  270. {
  271. if (_tcslen(pProvider->szProviderUpload) > 0)
  272. {
  273. retcode = TRUE;
  274. }
  275. pProvider = pProvider->pNext;
  276. } //end while
  277. g_pNetOpt->DestroyProviderList(&pProviderList);
  278. } //end if providers
  279. } //end if set up properly
  280. return (retcode);
  281. }
  282. STDMETHODIMP CCDNet::Download(DWORD dwDeviceHandle, TCHAR chDrive, DWORD dwMSID, LPCDTITLE pTitle, BOOL fManual, HWND hwndParent)
  283. {
  284. if (g_pNetOpt==NULL)
  285. {
  286. return E_FAIL;
  287. }
  288. if (g_pNetData==NULL)
  289. {
  290. return E_FAIL;
  291. }
  292. if (FAILED(g_pNetData->CheckDatabase(hwndParent)))
  293. {
  294. return E_FAIL;
  295. }
  296. CGetInfoFromNet netinfo(dwDeviceHandle,
  297. dwMSID,
  298. hwndParent);
  299. EnterCriticalSection(&g_Critical);
  300. g_fCancelDownload = FALSE;
  301. LeaveCriticalSection(&g_Critical);
  302. BOOL fResult = netinfo.DoIt(fManual, pTitle, chDrive);
  303. return fResult ? S_OK : E_FAIL;
  304. }
  305. STDMETHODIMP_(BOOL) CCDNet::IsDownloading()
  306. {
  307. BOOL retcode = FALSE;
  308. if (g_lNumDownloadingThreads > 0)
  309. {
  310. retcode = TRUE;
  311. }
  312. return (retcode);
  313. }
  314. STDMETHODIMP CCDNet::CancelDownload()
  315. {
  316. EnterCriticalSection(&g_Critical);
  317. if (g_pBind)
  318. {
  319. g_pBind->Abort();
  320. }
  321. g_fCancelDownload = TRUE;
  322. LeaveCriticalSection(&g_Critical);
  323. while (IsDownloading())
  324. {
  325. Sleep(10);
  326. }
  327. return S_OK;
  328. }
  329. struct CBindStatusCallback : IBindStatusCallback
  330. {
  331. ///// object state
  332. ULONG m_cRef; // object reference count
  333. BOOL m_fAbort; // set to true if we want this to abort
  334. HWND m_hMessage; // callback window
  335. IStream* m_pStream; // holds downloaded data
  336. ///// construction and destruction
  337. CBindStatusCallback(IStream* pStream, HWND hwndParent);
  338. ~CBindStatusCallback();
  339. ///// IUnknown methods
  340. STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
  341. STDMETHODIMP_(ULONG) AddRef();
  342. STDMETHODIMP_(ULONG) Release();
  343. ///// IBindStatusCallback methods
  344. STDMETHODIMP OnStartBinding(DWORD dwReserved, IBinding *pib);
  345. STDMETHODIMP GetPriority(LONG *pnPriority);
  346. STDMETHODIMP OnLowResource(DWORD reserved);
  347. STDMETHODIMP OnProgress(ULONG ulProgress, ULONG ulProgressMax,
  348. ULONG ulStatusCode, LPCWSTR szStatusText);
  349. STDMETHODIMP OnStopBinding(HRESULT hresult, LPCWSTR szError);
  350. STDMETHODIMP GetBindInfo(DWORD *grfBINDF, BINDINFO *pbindinfo);
  351. STDMETHODIMP OnDataAvailable(DWORD grfBSCF, DWORD dwSize,
  352. FORMATETC *pformatetc, STGMEDIUM *pstgmed);
  353. STDMETHODIMP OnObjectAvailable(REFIID riid, IUnknown *punk);
  354. };
  355. /////////////////////////////////////////////////////////////////////////////
  356. // CBindStatusCallback Creation & Destruction
  357. //
  358. CBindStatusCallback::CBindStatusCallback(IStream* pStream, HWND hwndParent)
  359. {
  360. HRESULT hr = S_OK;
  361. m_cRef = 0;
  362. m_fAbort = FALSE;
  363. m_pStream = pStream;
  364. m_pStream->AddRef();
  365. m_hMessage = hwndParent;
  366. PostMessage(m_hMessage,WM_NET_STATUS,(WPARAM)g_dllInst,IDS_STRING_CONNECTING);
  367. }
  368. CBindStatusCallback::~CBindStatusCallback()
  369. {
  370. EnterCriticalSection(&g_Critical);
  371. if (g_pBind)
  372. {
  373. g_pBind->Release();
  374. g_pBind = NULL;
  375. }
  376. LeaveCriticalSection(&g_Critical);
  377. if( m_pStream )
  378. {
  379. m_pStream->Release();
  380. m_pStream = NULL;
  381. }
  382. }
  383. /////////////////////////////////////////////////////////////////////////////
  384. // CBindStatusCallback IUnknown Methods
  385. //
  386. STDMETHODIMP CBindStatusCallback::QueryInterface(REFIID riid, LPVOID *ppvObj)
  387. {
  388. if (IsEqualIID(riid, IID_IUnknown) ||
  389. IsEqualIID(riid, IID_IBindStatusCallback))
  390. {
  391. *ppvObj = (IBindStatusCallback *) this;
  392. AddRef();
  393. return NOERROR;
  394. }
  395. else
  396. {
  397. *ppvObj = NULL;
  398. return E_NOINTERFACE;
  399. }
  400. }
  401. STDMETHODIMP_(ULONG) CBindStatusCallback::AddRef()
  402. {
  403. InterlockedIncrement((LONG*)&m_cRef);
  404. return m_cRef;
  405. }
  406. STDMETHODIMP_(ULONG) CBindStatusCallback::Release()
  407. {
  408. ULONG cRef = m_cRef;
  409. if (InterlockedDecrement((LONG*)&m_cRef) == 0)
  410. {
  411. delete this;
  412. return 0;
  413. }
  414. else
  415. return cRef-1;
  416. }
  417. /////////////////////////////////////////////////////////////////////////////
  418. // CBindStatusCallback IBindStatusCallback Methods
  419. //
  420. STDMETHODIMP CBindStatusCallback::OnStartBinding(DWORD dwReserved, IBinding *pib)
  421. {
  422. EnterCriticalSection(&g_Critical);
  423. g_pBind = pib;
  424. g_pBind->AddRef();
  425. LeaveCriticalSection(&g_Critical);
  426. return S_OK;
  427. }
  428. STDMETHODIMP CBindStatusCallback::GetPriority(LONG *pnPriority)
  429. {
  430. return S_OK;
  431. }
  432. STDMETHODIMP CBindStatusCallback::OnLowResource(DWORD reserved)
  433. {
  434. return S_OK;
  435. }
  436. STDMETHODIMP CBindStatusCallback::OnProgress(ULONG ulProgress, ULONG ulProgressMax,
  437. ULONG ulStatusCode, LPCWSTR szStatusText)
  438. {
  439. int nResID = 0;
  440. switch (ulStatusCode)
  441. {
  442. case (BINDSTATUS_FINDINGRESOURCE) : nResID = IDS_STRING_FINDINGRESOURCE; break;
  443. case (BINDSTATUS_CONNECTING) : nResID = IDS_STRING_CONNECTING; break;
  444. case (BINDSTATUS_REDIRECTING) : nResID = IDS_STRING_REDIRECTING; break;
  445. case (BINDSTATUS_BEGINDOWNLOADDATA) : nResID = IDS_STRING_BEGINDOWNLOAD; break;
  446. case (BINDSTATUS_DOWNLOADINGDATA) : nResID = IDS_STRING_DOWNLOAD; break;
  447. case (BINDSTATUS_ENDDOWNLOADDATA) : nResID = IDS_STRING_ENDDOWNLOAD; break;
  448. case (BINDSTATUS_SENDINGREQUEST) : nResID = IDS_STRING_SENDINGREQUEST; break;
  449. } //end switch
  450. if (nResID > 0)
  451. {
  452. PostMessage(m_hMessage,WM_NET_STATUS,(WPARAM)g_dllInst,nResID);
  453. }
  454. if (( m_fAbort ) || (g_fCancelDownload))
  455. {
  456. EnterCriticalSection(&g_Critical);
  457. g_fCancelDownload = TRUE;
  458. g_fDownloadDone = TRUE;
  459. LeaveCriticalSection(&g_Critical);
  460. return E_ABORT;
  461. }
  462. return S_OK;
  463. }
  464. STDMETHODIMP CBindStatusCallback::OnStopBinding(HRESULT hresult, LPCWSTR szError)
  465. {
  466. EnterCriticalSection(&g_Critical);
  467. if (g_pBind)
  468. {
  469. g_pBind->Release();
  470. g_pBind = NULL;
  471. }
  472. LeaveCriticalSection(&g_Critical);
  473. return S_OK;
  474. }
  475. STDMETHODIMP CBindStatusCallback::GetBindInfo(DWORD *pgrfBINDF, BINDINFO *pbindinfo)
  476. {
  477. *pgrfBINDF = 0;
  478. pbindinfo->cbSize = sizeof(BINDINFO);
  479. pbindinfo->szExtraInfo = NULL;
  480. ZeroMemory(&pbindinfo->stgmedData, sizeof(STGMEDIUM));
  481. pbindinfo->grfBindInfoF = 0;
  482. pbindinfo->dwBindVerb = BINDVERB_GET;
  483. pbindinfo->szCustomVerb = NULL;
  484. return S_OK;
  485. }
  486. STDMETHODIMP CBindStatusCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize,
  487. FORMATETC *pformatetc, STGMEDIUM *pstgmed)
  488. {
  489. // fill our stream with the data from the stream passed to us
  490. if( m_pStream )
  491. {
  492. ULARGE_INTEGER cb;
  493. cb.LowPart = dwSize;
  494. cb.HighPart = 0;
  495. if( pstgmed && pstgmed->pstm )
  496. {
  497. pstgmed->pstm->CopyTo( m_pStream, cb, NULL, NULL );
  498. }
  499. }
  500. // Notify owner when download is complete
  501. if( grfBSCF & BSCF_LASTDATANOTIFICATION )
  502. {
  503. g_fDownloadDone = TRUE;
  504. if( m_pStream )
  505. {
  506. m_pStream->Release();
  507. m_pStream = NULL;
  508. }
  509. }
  510. return S_OK;
  511. }
  512. STDMETHODIMP CBindStatusCallback::OnObjectAvailable(REFIID riid, IUnknown *punk)
  513. {
  514. return E_NOTIMPL;
  515. }
  516. /////////////////////////////////////////////////////////////////////////////
  517. // CGetInfoFromNet
  518. CGetInfoFromNet::CGetInfoFromNet(DWORD cdrom, DWORD dwMSID, HWND hwndParent)
  519. {
  520. DevHandle = cdrom;
  521. m_MS = dwMSID;
  522. g_hwndParent = hwndParent;
  523. }
  524. CGetInfoFromNet::~CGetInfoFromNet()
  525. {
  526. }
  527. BOOL CGetInfoFromNet::DoIt(BOOL fManual, LPCDTITLE pTitle, TCHAR chDrive)
  528. {
  529. BOOL fRet = FALSE;
  530. int nMode = CONNECTION_GETITNOW;
  531. if (!fManual)
  532. {
  533. if (g_lNumDownloadingThreads == 0)
  534. {
  535. //if no threads are running already,
  536. //check the connection, possibly prompting the user
  537. nMode = ConnectionCheck(g_hwndParent,g_pNetOpt, chDrive);
  538. }
  539. }
  540. if (nMode == CONNECTION_DONOTHING)
  541. {
  542. return FALSE;
  543. }
  544. //if passed-in ID is not > 0, then we don't want to scan current disc
  545. if ((m_MS > 0) && (pTitle == NULL))
  546. {
  547. m_Tracks = readtoc();
  548. if (m_Tracks > 0)
  549. {
  550. BuildQuery();
  551. }
  552. } //if msid is greater than 0
  553. if (nMode == CONNECTION_BATCH)
  554. {
  555. if (m_MS > 0)
  556. {
  557. AddToBatch(m_Tracks,m_Query);
  558. }
  559. return FALSE;
  560. }
  561. //we need to determine now whether we spawn a batching thread or a single-item downloader
  562. g_fDBWriteFailure = FALSE;
  563. DWORD dwThreadID;
  564. HANDLE hNetThread = NULL;
  565. //addref the global pointers before entering the thread
  566. g_pNetOpt->AddRef();
  567. g_pNetData->AddRef();
  568. if (m_MS > 0)
  569. {
  570. //need to create a batch item for this thread to use
  571. LPCDBATCH pBatch = new CDBATCH;
  572. pBatch->fRemove = FALSE;
  573. pBatch->fFresh = TRUE;
  574. pBatch->pNext = NULL;
  575. if (!pTitle)
  576. {
  577. pBatch->dwTitleID = m_MS;
  578. pBatch->dwNumTracks = m_Tracks;
  579. pBatch->szTitleQuery = new TCHAR[_tcslen(m_Query)+1];
  580. _tcscpy(pBatch->szTitleQuery,m_Query);
  581. }
  582. else
  583. {
  584. pBatch->dwTitleID = pTitle->dwTitleID;
  585. pBatch->dwNumTracks = pTitle->dwNumTracks;
  586. if (pTitle->szTitleQuery)
  587. {
  588. pBatch->szTitleQuery = new TCHAR[_tcslen(pTitle->szTitleQuery)+1];
  589. _tcscpy(pBatch->szTitleQuery,pTitle->szTitleQuery);
  590. }
  591. else
  592. {
  593. pBatch->szTitleQuery = new TCHAR[_tcslen(m_Query)+1];
  594. _tcscpy(pBatch->szTitleQuery,m_Query);
  595. }
  596. }
  597. hNetThread = CreateThread(NULL,0,SpawnSingleDownload,(void*)pBatch,0,&dwThreadID);
  598. }
  599. else
  600. {
  601. hNetThread = CreateThread(NULL,0,SpawnBatchDownload,(void*)NULL,0,&dwThreadID);
  602. }
  603. if (hNetThread)
  604. {
  605. CloseHandle(hNetThread);
  606. fRet = TRUE;
  607. }
  608. return (fRet);
  609. }
  610. int CGetInfoFromNet::readtoc()
  611. {
  612. DWORD dwRet;
  613. MCI_SET_PARMS mciSet;
  614. ZeroMemory( &mciSet, sizeof(mciSet) );
  615. mciSet.dwTimeFormat = MCI_FORMAT_MSF;
  616. mciSendCommand( DevHandle, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID)&mciSet );
  617. MCI_STATUS_PARMS mciStatus;
  618. long lAddress, lStartPos, lDiskLen;
  619. int i;
  620. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  621. mciStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
  622. //
  623. // NOTE: none of the mciSendCommand calls below bother to check the
  624. // return code. This is asking for trouble... but if the
  625. // commands fail we cannot do much about it.
  626. //
  627. dwRet = mciSendCommand( DevHandle, MCI_STATUS,
  628. MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus);
  629. int tracks = -1;
  630. tracks = (UCHAR)mciStatus.dwReturn;
  631. mciStatus.dwItem = MCI_STATUS_POSITION;
  632. for ( i = 0; i < tracks; i++ )
  633. {
  634. mciStatus.dwTrack = i + 1;
  635. dwRet = mciSendCommand( DevHandle, MCI_STATUS,
  636. MCI_STATUS_ITEM | MCI_TRACK,
  637. (DWORD_PTR)(LPVOID)&mciStatus);
  638. lAddress = (long)mciStatus.dwReturn;
  639. //converts "packed" time into pure frames
  640. lAddress = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
  641. (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
  642. (MCI_MSF_FRAME( lAddress));
  643. m_toc[i] = lAddress;
  644. if (i==0)
  645. {
  646. lStartPos = lAddress;
  647. }
  648. }
  649. mciStatus.dwItem = MCI_STATUS_LENGTH;
  650. dwRet = mciSendCommand( DevHandle, MCI_STATUS,
  651. MCI_STATUS_ITEM, (DWORD_PTR)(LPVOID)&mciStatus);
  652. /*
  653. ** Convert the total disk length into frames
  654. */
  655. lAddress = (long)mciStatus.dwReturn;
  656. lDiskLen = (MCI_MSF_MINUTE(lAddress) * FRAMES_PER_MINUTE) +
  657. (MCI_MSF_SECOND(lAddress) * FRAMES_PER_SECOND) +
  658. (MCI_MSF_FRAME( lAddress));
  659. /*
  660. ** Now, determine the absolute start position of the sentinel
  661. ** track. That is, the special track that marks the end of the
  662. ** disk.
  663. */
  664. lAddress = lStartPos + lDiskLen + 1; //dstewart: add one for true time
  665. m_toc[i] = lAddress;
  666. return (tracks);
  667. }
  668. void CGetInfoFromNet::BuildQuery()
  669. {
  670. wsprintf(m_Query,TEXT("cd=%X"),m_Tracks);
  671. //add each frame stattime to query, include end time of disc
  672. TCHAR tempstr[MAX_PATH];
  673. for (int i = 0; i < m_Tracks+1; i++)
  674. {
  675. wsprintf(tempstr,TEXT("+%X"),m_toc[i]);
  676. _tcscat(m_Query,tempstr);
  677. }
  678. }
  679. void CGetInfoFromNet::AddToBatch(int nNumTracks, TCHAR* szQuery)
  680. {
  681. if ((g_pNetData) && (g_pNetOpt))
  682. {
  683. g_pNetData->AddToBatch(m_MS, szQuery, nNumTracks);
  684. LPCDOPTIONS pOptions = g_pNetOpt->GetCDOpts();
  685. if (pOptions)
  686. {
  687. pOptions->dwBatchedTitles = g_pNetData->GetNumBatched();
  688. g_pNetOpt->DownLoadCompletion(0,NULL);
  689. }
  690. }
  691. }
  692. void CopyStreamToFile( IStream* pStream, HANDLE hFile )
  693. {
  694. TCHAR achBuf[512];
  695. ULONG cb = 1;
  696. DWORD dwWritten;
  697. LARGE_INTEGER dlib;
  698. dlib.LowPart = 0;
  699. dlib.HighPart = 0;
  700. pStream->Seek( dlib, STREAM_SEEK_SET, NULL );
  701. pStream->Read( achBuf, 512, &cb );
  702. while( cb )
  703. {
  704. if( FALSE == WriteFile( hFile, achBuf, cb, &dwWritten, NULL ))
  705. {
  706. break;
  707. }
  708. pStream->Read( achBuf, 512, &cb );
  709. }
  710. }
  711. BOOL DoDownload(TCHAR* url, TCHAR* szFilename, HWND hwndParent)
  712. {
  713. TCHAR szPath[_MAX_PATH];
  714. TCHAR sz[_MAX_PATH];
  715. BOOL fGotFileName = FALSE;
  716. // Get a file name
  717. if(GetTempPath(_MAX_PATH, szPath))
  718. {
  719. if(GetTempFileName(szPath, TEXT("cdd"), 0, sz))
  720. {
  721. fGotFileName = TRUE;
  722. }
  723. }
  724. if (!fGotFileName)
  725. {
  726. return FALSE;
  727. }
  728. IStream* pStream = NULL;
  729. g_fDownloadDone = FALSE;
  730. if (FAILED(CreateStreamOnHGlobal( NULL, TRUE, &pStream )))
  731. {
  732. return FALSE;
  733. }
  734. //pStream was addref'ed by createstreamonhgobal
  735. CBindStatusCallback* pCDC = new CBindStatusCallback(pStream, hwndParent);
  736. if(!pCDC)
  737. {
  738. pStream->Release();
  739. return FALSE;
  740. }
  741. pCDC->AddRef();
  742. HRESULT hr = E_NOTIMPL;
  743. if (g_hURLMon == NULL)
  744. {
  745. g_hURLMon = LoadLibrary(TEXT("URLMON.DLL"));
  746. }
  747. if (g_hURLMon!=NULL)
  748. {
  749. typedef BOOL (PASCAL *URLDOWNLOADPROC)(LPUNKNOWN, LPCTSTR, DWORD, LPBINDSTATUSCALLBACK);
  750. URLDOWNLOADPROC URLDownload = (URLDOWNLOADPROC)GetProcAddress(g_hURLMon,URLFUNCTION);
  751. if (URLDownload!=NULL)
  752. {
  753. #ifdef DBG
  754. OutputDebugString(url);
  755. OutputDebugString(TEXT("\n"));
  756. #endif
  757. hr = URLDownload(NULL, url, 0, pCDC);
  758. }
  759. }
  760. if(FAILED(hr))
  761. {
  762. pCDC->Release();
  763. pStream->Release();
  764. return FALSE;
  765. }
  766. pCDC->Release();
  767. if (g_fCancelDownload)
  768. {
  769. return FALSE;
  770. }
  771. // Create the file for writing
  772. HANDLE hFileWrite = CreateFile(sz, GENERIC_READ | GENERIC_WRITE,
  773. FILE_SHARE_READ | FILE_SHARE_WRITE,
  774. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
  775. if( hFileWrite != INVALID_HANDLE_VALUE )
  776. {
  777. CopyStreamToFile( pStream, hFileWrite );
  778. CloseHandle( hFileWrite );
  779. }
  780. pStream->Release();
  781. _tcscpy(szFilename,sz);
  782. return TRUE;
  783. }
  784. //dialog box handler for multiple hits
  785. INT_PTR CALLBACK MultiHitDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  786. {
  787. switch (message)
  788. {
  789. case WM_INITDIALOG :
  790. {
  791. TCHAR* szFilename = (TCHAR*)lParam;
  792. TCHAR szTemp[MAX_PATH];
  793. TCHAR szArtist[MAX_PATH];
  794. TCHAR szTitle[MAX_PATH];
  795. int i = 1;
  796. _tcscpy(szTitle,TEXT("."));
  797. while (_tcslen(szTitle)>0)
  798. {
  799. wsprintf(szTemp,TEXT("Title%i"),i);
  800. GetPrivateProfileString(TEXT("CD"),szTemp,TEXT(""),szTitle,sizeof(szTitle)/sizeof(TCHAR),szFilename);
  801. wsprintf(szTemp,TEXT("Artist%i"),i);
  802. GetPrivateProfileString(TEXT("CD"),szTemp,TEXT(""),szArtist,sizeof(szArtist)/sizeof(TCHAR),szFilename);
  803. i++;
  804. if (_tcslen(szTitle)>0)
  805. {
  806. wsprintf(szTemp,TEXT("%s (%s)"),szTitle,szArtist);
  807. SendDlgItemMessage(hwnd,IDC_LIST_DISCS,LB_ADDSTRING,0,(LPARAM)szTemp);
  808. }
  809. }
  810. SendDlgItemMessage(hwnd,IDC_LIST_DISCS,LB_SETCURSEL,0,0);
  811. }
  812. break;
  813. case WM_COMMAND :
  814. {
  815. if (LOWORD(wParam)==IDCANCEL)
  816. {
  817. EndDialog(hwnd,-1);
  818. }
  819. if (LOWORD(wParam)==IDOK)
  820. {
  821. LRESULT nSel = SendDlgItemMessage(hwnd,IDC_LIST_DISCS,LB_GETCURSEL,0,0);
  822. EndDialog(hwnd,nSel+1);
  823. }
  824. }
  825. break;
  826. }
  827. return FALSE;
  828. }
  829. BOOL ResolveMultiples(TCHAR* szFilename, BOOL fCurrent, HWND hwndParent)
  830. {
  831. //special case ... sometimes, this comes back with <2 hits!!!
  832. //in this case, go ahead and ask for URL1
  833. TCHAR sznewurl[INTERNET_MAX_URL_LENGTH];
  834. GetPrivateProfileString(TEXT("CD"),TEXT("URL2"),TEXT(""),sznewurl,sizeof(sznewurl)/sizeof(TCHAR),szFilename);
  835. INT_PTR nSelection = 0;
  836. if (_tcslen(sznewurl)==0)
  837. {
  838. nSelection = 1;
  839. }
  840. else
  841. {
  842. if (fCurrent)
  843. {
  844. nSelection = DialogBoxParam(g_dllInst, MAKEINTRESOURCE(IDD_MULTIPLE_HITS),
  845. hwndParent, MultiHitDlgProc, (LPARAM)szFilename );
  846. }
  847. }
  848. if (nSelection > 0)
  849. {
  850. TCHAR szSelected[MAX_PATH];
  851. wsprintf(szSelected,TEXT("URL%i"),nSelection);
  852. GetPrivateProfileString(TEXT("CD"),szSelected,TEXT(""),sznewurl,sizeof(sznewurl)/sizeof(TCHAR),szFilename);
  853. DeleteFile(szFilename);
  854. if (DoDownload(sznewurl,szFilename, hwndParent))
  855. {
  856. return TRUE;
  857. }
  858. }
  859. return FALSE;
  860. }
  861. //no more cover art in first version
  862. #if 0
  863. void TranslateTempCoverToFinal(TCHAR* szCurrent, TCHAR* szFinal, long discid, TCHAR* extension)
  864. {
  865. //we want to put the cover art in a "coverart" subdir relative to whereever CD player is
  866. TCHAR szPath[MAX_PATH];
  867. GetModuleFileName(NULL,szPath,sizeof(szPath));
  868. TCHAR* szPathEnd;
  869. szPathEnd = _tcsrchr(szPath, TEXT('\\'))+sizeof(TCHAR);
  870. _tcscpy(szPathEnd,TEXT("coverart\\"));
  871. CreateDirectory(szPath,NULL); //create the coverart subdir
  872. wsprintf(szFinal,TEXT("%s%08X%s"),szPath,discid,extension);
  873. }
  874. #endif
  875. DWORD GetNextDisc(long lOriginal, LPCDBATCH* ppBatch)
  876. {
  877. DWORD discid = (DWORD)-1;
  878. //only do the batch if no discid was passed in originally to thread
  879. if (lOriginal < 1)
  880. {
  881. if (*ppBatch!=NULL)
  882. {
  883. *ppBatch = (*ppBatch)->pNext;
  884. if (*ppBatch != NULL)
  885. {
  886. discid = (*ppBatch)->dwTitleID;
  887. }
  888. }
  889. }
  890. return (discid);
  891. }
  892. LPCDPROVIDER GetNewProvider(LPCDPROVIDER pList, LPCDPROVIDER pCurrent, LPCDPROVIDER pDefault)
  893. {
  894. //find the next provider that isn't the current
  895. if (pCurrent == pDefault)
  896. {
  897. //we've just done the current provider, so go to the head of the list next
  898. pCurrent = pList;
  899. if (pCurrent == pDefault)
  900. {
  901. //if the default was also the head of the list, go to the next and return
  902. pCurrent = pCurrent->pNext;
  903. }
  904. return (pCurrent);
  905. }
  906. //get the next entry on the list
  907. pCurrent = pCurrent->pNext;
  908. //is the next entry the same as the default entry? if so, move on one more
  909. if (pCurrent == pDefault)
  910. {
  911. pCurrent = pCurrent->pNext;
  912. }
  913. return (pCurrent);
  914. }
  915. //if szProvider is NULL, szURL is filled in with "just the query" ...
  916. //if szProvider is not NULL, it is prepended to the query in szURL
  917. int GetTracksAndQuery(LPCDBATCH pBatch, TCHAR* szURL, TCHAR* szProvider)
  918. {
  919. if (pBatch == NULL)
  920. {
  921. return 0;
  922. }
  923. int nReturn = pBatch->dwNumTracks;
  924. if (szProvider != NULL)
  925. {
  926. wsprintf(szURL,TEXT("%s%s"),szProvider,pBatch->szTitleQuery);
  927. }
  928. else
  929. {
  930. _tcscpy(szURL,pBatch->szTitleQuery);
  931. }
  932. return nReturn;
  933. }
  934. void WINAPI AddTitleToDatabase(DWORD dwDiscID, DWORD dwTracks, TCHAR *szURL, TCHAR *szTempFile)
  935. {
  936. LPCDTITLE pCDTitle = NULL;
  937. TCHAR tempstr[CDSTR];
  938. BOOL fContinue = TRUE;
  939. DWORD dwMenus = 0;
  940. while (fContinue)
  941. {
  942. TCHAR szMenuIndex[10];
  943. TCHAR szMenuEntry[INTERNET_MAX_URL_LENGTH];
  944. wsprintf(szMenuIndex,TEXT("MENU%i"),dwMenus+1);
  945. GetPrivateProfileString( TEXT("CD"), szMenuIndex, TEXT(""),
  946. szMenuEntry, sizeof(szMenuEntry)/sizeof(TCHAR), szTempFile );
  947. if (_tcslen(szMenuEntry)>0)
  948. {
  949. dwMenus++;
  950. }
  951. else
  952. {
  953. fContinue = FALSE;
  954. }
  955. }
  956. if (SUCCEEDED(g_pNetData->CreateTitle(&pCDTitle, dwDiscID, dwTracks, dwMenus)))
  957. {
  958. GetPrivateProfileString(TEXT("CD"),TEXT("TITLE"),TEXT(""),tempstr,sizeof(tempstr)/sizeof(TCHAR),szTempFile);
  959. _tcscpy(pCDTitle->szTitle,tempstr);
  960. GetPrivateProfileString(TEXT("CD"),TEXT("ARTIST"),TEXT(""),tempstr,sizeof(tempstr)/sizeof(TCHAR),szTempFile);
  961. _tcscpy(pCDTitle->szArtist,tempstr);
  962. GetPrivateProfileString(TEXT("CD"),TEXT("LABEL"),TEXT(""),tempstr,sizeof(tempstr)/sizeof(TCHAR),szTempFile);
  963. _tcscpy(pCDTitle->szLabel,tempstr);
  964. GetPrivateProfileString(TEXT("CD"),TEXT("COPYRIGHT"),TEXT(""),tempstr,sizeof(tempstr)/sizeof(TCHAR),szTempFile);
  965. _tcscpy(pCDTitle->szCopyright,tempstr);
  966. GetPrivateProfileString(TEXT("CD"),TEXT("RELEASEDATE"),TEXT(""),tempstr,sizeof(tempstr)/sizeof(TCHAR),szTempFile);
  967. _tcscpy(pCDTitle->szDate,tempstr);
  968. g_pNetData->SetTitleQuery(pCDTitle, szURL);
  969. for (int i = 1; i < (int) dwTracks + 1; i++)
  970. {
  971. TCHAR tempstrtrack[10];
  972. TCHAR tempstrtitle[CDSTR];
  973. wsprintf(tempstrtrack,TEXT("TRACK%i"),i);
  974. GetPrivateProfileString(TEXT("CD"),tempstrtrack,TEXT(""),tempstrtitle,sizeof(tempstrtitle)/sizeof(TCHAR),szTempFile);
  975. if (_tcslen(tempstrtitle) == 0)
  976. {
  977. TCHAR strFormat[CDSTR];
  978. LoadString(g_dllInst,IDS_STRING_DEFAULTTRACK,strFormat,sizeof(strFormat)/sizeof(TCHAR));
  979. wsprintf(tempstrtitle,strFormat,i);
  980. }
  981. _tcscpy(pCDTitle->pTrackTable[i-1].szName,tempstrtitle);
  982. }
  983. for (i = 1; i < (int) (dwMenus + 1); i++)
  984. {
  985. TCHAR tempstrmenu[10];
  986. TCHAR tempstrmenuvalue[CDSTR+INTERNET_MAX_URL_LENGTH+(3*sizeof(TCHAR))]; //3 = two colons and a terminating null
  987. wsprintf(tempstrmenu,TEXT("MENU%i"),i);
  988. GetPrivateProfileString(TEXT("CD"),tempstrmenu,TEXT(""),tempstrmenuvalue,sizeof(tempstrmenuvalue)/sizeof(TCHAR),szTempFile);
  989. //need to split menu into its component parts
  990. if (_tcslen(tempstrmenuvalue)!=0)
  991. {
  992. TCHAR* szNamePart;
  993. szNamePart = _tcsstr(tempstrmenuvalue,URL_SEPARATOR);
  994. TCHAR* szURLPart;
  995. szURLPart = _tcsstr(tempstrmenuvalue,URL_SEPARATOR);
  996. if (szURLPart!=NULL)
  997. {
  998. //need to move past two colons
  999. szURLPart = _tcsinc(szURLPart);
  1000. szURLPart = _tcsinc(szURLPart);
  1001. }
  1002. if (szNamePart!=NULL)
  1003. {
  1004. *szNamePart = '\0';
  1005. }
  1006. if (tempstrmenuvalue)
  1007. {
  1008. if (_tcslen(tempstrmenuvalue) >= sizeof(pCDTitle->pMenuTable[i-1].szMenuText)/sizeof(TCHAR))
  1009. {
  1010. tempstrmenuvalue[sizeof(pCDTitle->pMenuTable[i-1].szMenuText)/sizeof(TCHAR) - 1] = TEXT('\0'); // Trunc string to max len
  1011. }
  1012. _tcscpy(pCDTitle->pMenuTable[i-1].szMenuText,tempstrmenuvalue);
  1013. }
  1014. if (szURLPart)
  1015. {
  1016. g_pNetData->SetMenuQuery(&(pCDTitle->pMenuTable[i-1]), szURLPart);
  1017. }
  1018. }
  1019. }
  1020. g_pNetData->UnlockTitle(pCDTitle,TRUE);
  1021. //at this point, if the title is not in the database, we have a major problem
  1022. if (!g_pNetData->QueryTitle(dwDiscID))
  1023. {
  1024. g_fDBWriteFailure = TRUE;
  1025. }
  1026. else
  1027. {
  1028. g_fDBWriteFailure = FALSE;
  1029. }
  1030. }
  1031. }
  1032. BOOL IsCertifiedProvider(LPCDPROVIDER pProvider, TCHAR *szTempFile)
  1033. {
  1034. BOOL fCertified = TRUE;
  1035. TCHAR szCert[MAX_PATH];
  1036. GetPrivateProfileString(TEXT("CD"),TEXT("CERTIFICATE"),TEXT(""),szCert,sizeof(szCert)/sizeof(TCHAR),szTempFile);
  1037. fCertified = g_pNetOpt->VerifyProvider(pProvider,szCert);
  1038. return(fCertified);
  1039. }
  1040. void UpdatePropertyPage(DWORD dwDiscID, BOOL fDownloading, HWND hwndParent)
  1041. {
  1042. if (g_pNetOpt)
  1043. {
  1044. LPCDUNIT pUnit = g_pNetOpt->GetCDOpts()->pCDUnitList;
  1045. while (pUnit!=NULL)
  1046. {
  1047. if (pUnit->dwTitleID == dwDiscID)
  1048. {
  1049. pUnit->fDownLoading = fDownloading;
  1050. PostMessage(hwndParent,WM_NET_DB_UPDATE_DISC,0,(LPARAM)pUnit); //Tell the UI we changed status of disc
  1051. break;
  1052. }
  1053. pUnit = pUnit->pNext;
  1054. }
  1055. }
  1056. }
  1057. BOOL WINAPI DownloadBatch(LPCDBATCH pBatch, LPCDPROVIDER pProvider, LPDWORD pdwMultiHit, LPBOOL pfTimeout, HWND hwndParent)
  1058. {
  1059. BOOL fSuccess = FALSE;
  1060. DWORD dwTracks;
  1061. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  1062. TCHAR szTempFile[MAX_PATH];
  1063. DWORD dwDiscID;
  1064. dwTracks = GetTracksAndQuery(pBatch, szURL, pProvider->szProviderURL);
  1065. dwDiscID = pBatch->dwTitleID;
  1066. *pfTimeout = FALSE;
  1067. UpdatePropertyPage(pBatch->dwTitleID, TRUE, hwndParent); //tell prop page ui that disc is downloading
  1068. if (dwTracks > 0 && dwDiscID != 0)
  1069. {
  1070. if (DoDownload(szURL,szTempFile,hwndParent))
  1071. {
  1072. if (IsCertifiedProvider(pProvider, szTempFile))
  1073. {
  1074. int nMode = GetPrivateProfileInt(TEXT("CD"),TEXT("MODE"),MODE_NOT_FOUND,szTempFile);
  1075. if (nMode == MODE_NOT_FOUND)
  1076. {
  1077. DeleteFile(szTempFile);
  1078. }
  1079. else if (nMode == MODE_MULTIPLE)
  1080. {
  1081. if (pdwMultiHit)
  1082. {
  1083. (*pdwMultiHit)++;
  1084. }
  1085. if (!ResolveMultiples(szTempFile,TRUE,hwndParent))
  1086. {
  1087. DeleteFile(szTempFile);
  1088. }
  1089. else
  1090. {
  1091. nMode = MODE_OK;
  1092. }
  1093. }
  1094. if (nMode == MODE_OK)
  1095. {
  1096. GetTracksAndQuery(pBatch,szURL,NULL); //reset szURL to lose the provider
  1097. AddTitleToDatabase(dwDiscID, dwTracks, szURL, szTempFile);
  1098. DeleteFile(szTempFile);
  1099. fSuccess = TRUE;
  1100. } //end if mode ok
  1101. } //end if certified provider
  1102. } //end if download ok
  1103. else
  1104. {
  1105. *pfTimeout = TRUE;
  1106. }
  1107. } //end if valid query
  1108. UpdatePropertyPage(pBatch->dwTitleID, FALSE, hwndParent); //tell prop page ui that disc is no longer downloading
  1109. return(fSuccess);
  1110. }
  1111. DWORD WINAPI SpawnSingleDownload(LPVOID pParam)
  1112. {
  1113. InterlockedIncrement((LONG*)&g_lNumDownloadingThreads);
  1114. LPCDBATCH pBatch = (LPCDBATCH)pParam;
  1115. HWND hwndParent = g_hwndParent;
  1116. if (pBatch)
  1117. {
  1118. DoBatchDownload(pBatch,hwndParent);
  1119. //if download failed, add to batch if not already in db
  1120. //but only do this if batching is turned on
  1121. LPCDOPTIONS pOptions = g_pNetOpt->GetCDOpts();
  1122. if (pOptions)
  1123. {
  1124. LPCDOPTDATA pOptionData = pOptions->pCDData;
  1125. if (pOptionData)
  1126. {
  1127. if (pOptionData->fBatchEnabled)
  1128. {
  1129. if (!g_pNetData->QueryTitle(pBatch->dwTitleID))
  1130. {
  1131. g_pNetData->AddToBatch(pBatch->dwTitleID, pBatch->szTitleQuery, pBatch->dwNumTracks);
  1132. pOptions->dwBatchedTitles = g_pNetData->GetNumBatched();
  1133. PostMessage(hwndParent,WM_NET_DB_UPDATE_BATCH,0,0); //Tell the UI we changed number in batch
  1134. } //end if not in db
  1135. } //if batching is on
  1136. } //end if option data
  1137. } //end if poptions
  1138. delete [] pBatch->szTitleQuery;
  1139. delete pBatch;
  1140. }
  1141. //addref'ed before thread was created
  1142. g_pNetOpt->Release();
  1143. g_pNetData->Release();
  1144. InterlockedDecrement((LONG*)&g_lNumDownloadingThreads);
  1145. return 0;
  1146. }
  1147. DWORD WINAPI SpawnBatchDownload(LPVOID pParam)
  1148. {
  1149. InterlockedIncrement((LONG*)&g_lNumDownloadingThreads);
  1150. LPCDBATCH pBatchList = NULL;
  1151. HWND hwndParent = g_hwndParent;
  1152. if (g_pNetData)
  1153. {
  1154. if (SUCCEEDED(g_pNetData->LoadBatch(NULL,&pBatchList)))
  1155. {
  1156. DoBatchDownload(pBatchList,hwndParent);
  1157. g_pNetData->UnloadBatch(pBatchList);
  1158. }
  1159. }
  1160. //addref'ed before thread was created
  1161. g_pNetOpt->Release();
  1162. g_pNetData->Release();
  1163. InterlockedDecrement((LONG*)&g_lNumDownloadingThreads);
  1164. return 0;
  1165. }
  1166. DWORD WINAPI DoBatchDownload(LPCDBATCH pBatchList, HWND hwndParent)
  1167. {
  1168. EnterCriticalSection(&g_BatchCrit);
  1169. BOOL retcode = FALSE;
  1170. DWORD dwHow;
  1171. BOOL fConnected;
  1172. DWORD dwCurrent = 0;
  1173. DWORD dwOther = 0;
  1174. DWORD dwMultiHit = 0;
  1175. DWORD dwTimedOut = 0;
  1176. fConnected = _InternetGetConnectedState(&dwHow,0,TRUE); // Make sure we are connected to net
  1177. if (fConnected && g_pNetOpt && g_pNetData) // Make sure we are in a valid state
  1178. {
  1179. LPCDOPTIONS pOptions = g_pNetOpt->GetCDOpts(); // Get the options, needed for provider list
  1180. if (pOptions && pOptions->pCurrentProvider) // Make sure we have providers
  1181. {
  1182. LPCDPROVIDER pProviderList = NULL;
  1183. LPCDPROVIDER pProvider = NULL;
  1184. g_pNetOpt->CreateProviderList(&pProviderList); // Get the sorted provider list
  1185. pProvider = pProviderList; // Get the head of the list
  1186. LPCDBATCH pBatch;
  1187. if (pBatchList)
  1188. {
  1189. while (pProvider && !g_fCancelDownload) // loop thru providers, but check current first and only once.
  1190. {
  1191. BOOL fNotifiedUIProvider = FALSE;
  1192. pBatch = pBatchList;
  1193. while (pBatch && !g_fCancelDownload && !pProvider->fTimedOut) // We will loop thru each batched title
  1194. {
  1195. BOOL fAttemptDownload = TRUE; // Assume we are going to try to download all in batch
  1196. if (pBatch->fRemove)
  1197. {
  1198. fAttemptDownload = FALSE; //we've already tried this disc on one provider and got it
  1199. }
  1200. if (fAttemptDownload)
  1201. {
  1202. if (!fNotifiedUIProvider)
  1203. {
  1204. PostMessage(hwndParent,WM_NET_CHANGEPROVIDER,0,(LPARAM)pProvider); //Tell the UI who the provider is
  1205. fNotifiedUIProvider = TRUE;
  1206. }
  1207. BOOL fTimeout = FALSE;
  1208. if (DownloadBatch(pBatch, pProvider, &dwMultiHit, &fTimeout, hwndParent)) // attempt to download this batch
  1209. {
  1210. pBatch->fRemove = TRUE; // This batch download succeeded, mark for termination from batch
  1211. if (pProvider == pOptions->pCurrentProvider)
  1212. {
  1213. dwCurrent++;
  1214. }
  1215. else
  1216. {
  1217. dwOther++;
  1218. }
  1219. }
  1220. else
  1221. {
  1222. pProvider->fTimedOut = fTimeout;
  1223. }
  1224. //check to see if db write failed
  1225. if (g_fDBWriteFailure)
  1226. {
  1227. //let the UI know
  1228. PostMessage(hwndParent,WM_NET_DB_FAILURE,0,0);
  1229. //get out of the batch loop
  1230. break;
  1231. }
  1232. //let ui know that something happened with this disc
  1233. PostMessage(hwndParent,WM_NET_DONE,(WPARAM)g_dllInst,pBatch->dwTitleID);
  1234. //increment the meter if we know this is the last time we're
  1235. //visiting this particular disc ... either it was found, or
  1236. //we are out of possible places to look
  1237. if ((pBatch->fRemove) || (pProvider->pNext == NULL))
  1238. {
  1239. PostMessage(hwndParent,WM_NET_INCMETER,(WPARAM)g_dllInst,pBatch->dwTitleID);
  1240. }
  1241. } //end attempt on disc
  1242. pBatch = pBatch->pNext;
  1243. } //end batch
  1244. if (g_fDBWriteFailure)
  1245. {
  1246. //get out of the provider loop
  1247. break;
  1248. }
  1249. pProvider = pProvider->pNext; //providers are "in order"
  1250. } //end while cycling providers
  1251. } //end if load batch OK
  1252. //check to see if ALL providers timed out ... possible net problem
  1253. BOOL fAllFailed = TRUE;
  1254. pProvider = pProviderList;
  1255. while (pProvider!=NULL)
  1256. {
  1257. if (!pProvider->fTimedOut)
  1258. {
  1259. fAllFailed = FALSE;
  1260. break;
  1261. }
  1262. pProvider = pProvider->pNext;
  1263. }
  1264. if (fAllFailed)
  1265. {
  1266. //let the UI know
  1267. PostMessage(hwndParent,WM_NET_NET_FAILURE,0,0);
  1268. }
  1269. g_pNetOpt->DestroyProviderList(&pProviderList);
  1270. } //end if pointers ok
  1271. #ifdef DBG
  1272. // Ok, output some interesting stat's about what happened.
  1273. {
  1274. TCHAR str[255];
  1275. wsprintf(str, TEXT("current = %d, other = %d, multihits = %d\n"), dwCurrent, dwOther, dwMultiHit);
  1276. OutputDebugString(str);
  1277. }
  1278. #endif
  1279. } //end if connected to net and pointers ok
  1280. if (!fConnected)
  1281. {
  1282. //may be a net problem
  1283. if ((dwHow & (INTERNET_CONNECTION_MODEM|INTERNET_CONNECTION_LAN)) == 0)
  1284. {
  1285. PostMessage(hwndParent,WM_NET_NET_FAILURE,0,0);
  1286. }
  1287. }
  1288. PostMessage(hwndParent,WM_NET_DONE,(WPARAM)g_dllInst,(LPARAM) 0); //fBadGuy ? -1 : 0);
  1289. LeaveCriticalSection(&g_BatchCrit);
  1290. return (retcode);
  1291. }