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.

2672 lines
69 KiB

  1. //--------------------------------------------------------------------------;
  2. //
  3. // File: cddb.cpp
  4. //
  5. // Copyright (c) 1998 Microsoft Corporation. All rights reserved
  6. //
  7. //--------------------------------------------------------------------------;
  8. #include "precomp.h"
  9. #include "cdopti.h"
  10. #include "cddata.h"
  11. #define SECTION_BUFFER (512)
  12. #define PLAYLIST_BUFFER (255)
  13. #define BUFFERINC (128)
  14. #define MAXNUMPLAY (127)
  15. #define ROWSET 1
  16. #ifndef SQL_SUCCEEDED
  17. #define SQL_SUCCEEDED(rc) (((rc)&(~1))==0)
  18. #endif
  19. #ifndef SQL_W_CHAR
  20. #define SQL_C_WCHAR (-8)
  21. #endif
  22. #ifndef SQL_LONGCHAR_FIELD
  23. #define SQL_LONGCHAR_FIELD (-10)
  24. #endif
  25. const TCHAR gszIniFile[] = TEXT("cdplayer.ini");
  26. const TCHAR gszDefault[] = TEXT("\0");
  27. const TCHAR gszArtist[] = TEXT("artist");
  28. const TCHAR gszTitle[] = TEXT("title");
  29. const TCHAR gszNumTracks[] = TEXT("numtracks");
  30. const TCHAR gszOrder[] = TEXT("order");
  31. const TCHAR gszNumPlay[] = TEXT("numplay");
  32. const TCHAR gszDriverName[] = TEXT("Microsoft Access Driver (*.mdb)");
  33. const TCHAR gszDSNAttr[] = TEXT("DSN=DeluxeCD%cDefaultDir=%s%cDriverID=25%cDBQ=DeluxeCD.mdb%c");
  34. const TCHAR gszDSNCreate[] = TEXT("CREATE_DB=%s\\DeluxeCD.mdb%c");
  35. const TCHAR gszTitleTable[] = TEXT("Titles");
  36. const TCHAR gszTrackTable[] = TEXT("Tracks");
  37. const TCHAR gszMenuTable[] = TEXT("Menus");
  38. const TCHAR gszBatchTable[] = TEXT("Batch");
  39. TCHAR gszDSN[] = TEXT("DeluxeCD");
  40. TCHAR gszTitlesCreate[] = TEXT("create table Titles ")
  41. TEXT("(")
  42. TEXT("TitleID long, ")
  43. TEXT("Artist longchar, ")
  44. TEXT("Title longchar, ")
  45. TEXT("Copyright longchar, ")
  46. TEXT("Label longchar, ")
  47. TEXT("ReleaseDate longchar, ")
  48. TEXT("NumTracks long, ")
  49. TEXT("NumMenus long, ")
  50. TEXT("PlayList longchar, ")
  51. TEXT("TitleQuery longchar ")
  52. TEXT(")");
  53. TCHAR gszTracksCreate[] = TEXT("create table Tracks ")
  54. TEXT("(")
  55. TEXT("TitleID long, ")
  56. TEXT("TrackID long, ")
  57. TEXT("TrackName longchar ")
  58. TEXT(")");
  59. TCHAR gszMenusCreate[] = TEXT("create table Menus ")
  60. TEXT("(")
  61. TEXT("TitleID long, ")
  62. TEXT("MenuID long, ")
  63. TEXT("MenuName longchar, ")
  64. TEXT("MenuQuery longchar ")
  65. TEXT(")");
  66. TCHAR gszBatchCreate[] = TEXT("create table Batch ")
  67. TEXT("(")
  68. TEXT("TitleID long, ")
  69. TEXT("NumTracks long, ")
  70. TEXT("TitleQuery longchar")
  71. TEXT(")");
  72. SDWORD gcbTitles[] = { 0, SQL_NTS, SQL_NTS, SQL_NTS, SQL_NTS, SQL_NTS, 0, 0, SQL_NTS, INTERNET_MAX_PATH_LENGTH };
  73. SDWORD gcbTracks[] = { 0, 0, SQL_NTS };
  74. SDWORD gcbMenus[] = { 0, 0, SQL_NTS, INTERNET_MAX_PATH_LENGTH };
  75. SDWORD gcbBatch[] = { 0, 0, INTERNET_MAX_PATH_LENGTH };
  76. extern HINSTANCE g_dllInst;
  77. ////////////
  78. // Functions
  79. ////////////
  80. CCDData::CCDData()
  81. {
  82. m_pTitleList = NULL;
  83. m_pBatchList = NULL;
  84. m_dwLoadCnt = 0;
  85. m_dwBatchCnt = 0;
  86. m_henv = NULL;
  87. m_hdbc = NULL;
  88. m_fToldUser = FALSE;
  89. m_pSQL = NULL;
  90. m_dwRef = 0;
  91. memset(&m_bd, 0, sizeof(m_bd));
  92. InitializeCriticalSection(&m_crit);
  93. }
  94. CCDData::~CCDData()
  95. {
  96. CloseDatabase();
  97. if (m_pTitleList)
  98. {
  99. DestroyTitles(&m_pTitleList);
  100. }
  101. if (m_pSQL)
  102. {
  103. delete m_pSQL;
  104. }
  105. DeleteCriticalSection(&m_crit);
  106. }
  107. STDMETHODIMP CCDData::QueryInterface(REFIID riid, void** ppv)
  108. {
  109. *ppv = NULL;
  110. if (IID_IUnknown == riid || IID_ICDData == riid)
  111. {
  112. *ppv = this;
  113. }
  114. if (NULL==*ppv)
  115. {
  116. return E_NOINTERFACE;
  117. }
  118. AddRef();
  119. return S_OK;
  120. }
  121. STDMETHODIMP CCDData::GetSQLPtr(BOOL fInited)
  122. {
  123. HRESULT hr = S_OK;
  124. if (m_pSQL == NULL)
  125. {
  126. static BOOL fAttempt = FALSE;
  127. if (!fAttempt)
  128. {
  129. m_pSQL = new SQL;
  130. if (m_pSQL && !m_pSQL->Initialize())
  131. {
  132. delete m_pSQL;
  133. m_pSQL = NULL;
  134. hr = E_FAIL;
  135. }
  136. else
  137. {
  138. if (!fInited) // we must be running in shell mode, quietly initialize
  139. {
  140. Initialize(NULL);
  141. CheckDatabase(NULL);
  142. }
  143. }
  144. }
  145. else
  146. {
  147. hr = E_FAIL;
  148. }
  149. fAttempt = TRUE;
  150. }
  151. return(hr);
  152. }
  153. STDMETHODIMP_(ULONG) CCDData::AddRef(void)
  154. {
  155. return ++m_dwRef;
  156. }
  157. STDMETHODIMP_(ULONG) CCDData::Release(void)
  158. {
  159. if (0!=--m_dwRef)
  160. return m_dwRef;
  161. delete this;
  162. return 0;
  163. }
  164. STDMETHODIMP_(void) CCDData::Enter(void)
  165. {
  166. EnterCriticalSection(&m_crit);
  167. }
  168. STDMETHODIMP_(void) CCDData::Leave(void)
  169. {
  170. LeaveCriticalSection(&m_crit);
  171. }
  172. STDMETHODIMP CCDData::GetUnknownString(TCHAR **ppStr, const TCHAR *szSection, const TCHAR *szEntry, DWORD dwInitialAlloc)
  173. {
  174. TCHAR *pStr;
  175. DWORD dwSize;
  176. DWORD dwResult;
  177. HRESULT hr = S_OK;
  178. dwSize = dwInitialAlloc - BUFFERINC;
  179. pStr = NULL;
  180. do
  181. {
  182. dwSize += BUFFERINC;
  183. if (pStr)
  184. {
  185. delete pStr;
  186. }
  187. pStr = new(TCHAR[dwSize]);
  188. if (pStr == NULL)
  189. {
  190. hr = E_OUTOFMEMORY;
  191. break;
  192. }
  193. dwResult = GetPrivateProfileString(szSection, szEntry, TEXT("\0"), pStr, dwSize, gszIniFile);
  194. }
  195. while (dwResult == (dwSize - 2));
  196. *ppStr = pStr;
  197. return(hr);
  198. }
  199. STDMETHODIMP_(void) CCDData::ImportTrack(TCHAR *szDiscID, DWORD dwTrack)
  200. {
  201. TCHAR szTrack[6];
  202. wsprintf(szTrack,TEXT("%d"),dwTrack);
  203. GetPrivateProfileString(szDiscID,szTrack,gszDefault,m_bd.CDTrack.szName,CDSTR,gszIniFile);
  204. }
  205. STDMETHODIMP_(RETCODE) CCDData::ImportTracks(HSTMT hstmt, TCHAR *szDiscID)
  206. {
  207. RETCODE rc = SQL_SUCCESS;
  208. for (DWORD dwTrack = 0; dwTrack < m_bd.CDTitle.dwNumTracks; dwTrack++)
  209. {
  210. ImportTrack(szDiscID, dwTrack);
  211. rc = m_pSQL->SetPos(hstmt, 0, SQL_ADD, SQL_LOCK_NO_CHANGE);
  212. if (rc == SQL_SUCCESS)
  213. {
  214. m_bd.dwTrackID++;
  215. }
  216. else
  217. {
  218. ReportError(&m_bd, hstmt);
  219. break;
  220. }
  221. }
  222. return(rc);
  223. }
  224. STDMETHODIMP CCDData::ImportTitle(TCHAR *szDiscID)
  225. {
  226. HRESULT hr = S_OK;
  227. DWORD dwTitleID;
  228. _stscanf(szDiscID,TEXT("%xd"),&dwTitleID);
  229. if (dwTitleID == CDTITLE_NODISC)
  230. {
  231. hr = E_INVALIDARG;
  232. }
  233. else
  234. {
  235. m_bd.CDTitle.dwTitleID = dwTitleID;
  236. m_bd.CDTitle.dwNumTracks = GetPrivateProfileInt(szDiscID,gszNumTracks,0,gszIniFile);
  237. m_bd.CDTitle.dwNumPlay = GetPrivateProfileInt(szDiscID,gszNumPlay,0,gszIniFile);
  238. GetPrivateProfileString(szDiscID, gszArtist, gszDefault, m_bd.CDTitle.szArtist, CDSTR, gszIniFile);
  239. GetPrivateProfileString(szDiscID, gszTitle, gszDefault, m_bd.CDTitle.szTitle, CDSTR, gszIniFile);
  240. m_bd.szPlayList[0] = TEXT('\0');
  241. m_bd.szQuery[0] = TEXT('\0');
  242. if (m_bd.CDTitle.dwNumPlay)
  243. {
  244. TCHAR *pPlayTable = NULL;
  245. TCHAR *pText = NULL;
  246. DWORD dwIndex;
  247. int iNum;
  248. TCHAR *pDst = m_bd.szPlayList;
  249. m_bd.CDTitle.dwNumPlay = min(m_bd.CDTitle.dwNumPlay, MAXNUMPLAY);
  250. if (FAILED(GetUnknownString(&pPlayTable, szDiscID, gszOrder, PLAYLIST_BUFFER)))
  251. {
  252. m_bd.CDTitle.dwNumPlay = 0;
  253. }
  254. else
  255. {
  256. pText = pPlayTable;
  257. for (dwIndex = 0; dwIndex < m_bd.CDTitle.dwNumPlay && *pText; dwIndex++)
  258. {
  259. _stscanf(pText,TEXT("%d"), &iNum);
  260. wsprintf(pDst, TEXT("%02x"), iNum);
  261. while(*pDst != TEXT('\0'))
  262. {
  263. pDst++;
  264. }
  265. while(isdigit(*pText++));
  266. }
  267. delete pPlayTable;
  268. }
  269. }
  270. }
  271. return(hr);
  272. }
  273. STDMETHODIMP_(void) CCDData::ImportDatabase(LPTIMEDMETER ptm, HSTMT *hstmt, TCHAR *szDiscID)
  274. {
  275. DWORD dwCount = 0;
  276. RETCODE rc;
  277. while(*szDiscID)
  278. {
  279. m_bd.dwTrackID = 0;
  280. m_bd.dwMenuID = 0;
  281. if (SUCCEEDED(ImportTitle(szDiscID)))
  282. {
  283. rc = ImportTracks(hstmt[1], szDiscID);
  284. if (rc == SQL_SUCCESS)
  285. {
  286. rc = m_pSQL->SetPos(hstmt[0], 0, SQL_ADD, SQL_LOCK_NO_CHANGE);
  287. ReportError(&m_bd, hstmt);
  288. }
  289. if (!SQL_SUCCEEDED(rc))
  290. {
  291. break;
  292. }
  293. }
  294. UpdateMeter(ptm);
  295. while(*szDiscID++);
  296. }
  297. }
  298. STDMETHODIMP_(DWORD) CCDData::ImportCount(TCHAR *pEntries)
  299. {
  300. TCHAR *szDiscID = pEntries;
  301. DWORD dwCount = 0;
  302. while(*szDiscID)
  303. {
  304. dwCount++;
  305. while(*szDiscID++);
  306. }
  307. return(dwCount);
  308. }
  309. STDMETHODIMP_(void) CCDData::CreateMeter(LPTIMEDMETER ptm, HWND hWnd, DWORD dwCount, DWORD dwJump, UINT uStringID)
  310. {
  311. if (hWnd && ptm)
  312. {
  313. ptm->hMeter = CreateDialog(g_dllInst,MAKEINTRESOURCE(IDD_LOADSTATUS),hWnd,(DLGPROC) MeterHandler);
  314. if (ptm->hMeter)
  315. {
  316. ptm->hParent = hWnd;
  317. ptm->dwStartTime = timeGetTime();
  318. ptm->dwRange = dwCount;
  319. ptm->fShowing = FALSE;
  320. ptm->dwCount = 0;
  321. ptm->dwShowCount = 0;
  322. ptm->dwJump = dwJump;
  323. if (uStringID != 0)
  324. {
  325. TCHAR szTitle[255];
  326. LoadString(g_dllInst, uStringID, szTitle, sizeof(szTitle)/sizeof(TCHAR));
  327. SetWindowText(ptm->hMeter, szTitle);
  328. }
  329. }
  330. }
  331. else
  332. {
  333. if (ptm)
  334. {
  335. memset(ptm, 0, sizeof(TIMEDMETER));
  336. }
  337. }
  338. }
  339. STDMETHODIMP_(void) CCDData::UpdateMeter(LPTIMEDMETER ptm)
  340. {
  341. if (ptm && ptm->hMeter)
  342. {
  343. ptm->dwCount++;
  344. if (ptm->fShowing)
  345. {
  346. if (ptm->hMeter && ((ptm->dwCount % ptm->dwJump) == 0))
  347. {
  348. SendDlgItemMessage( ptm->hMeter, IDC_PROGRESSMETER, PBM_SETPOS, (WPARAM) ptm->dwCount - ptm->dwShowCount, 0);
  349. }
  350. }
  351. else
  352. {
  353. if ((ptm->dwCount % ptm->dwJump) == 0)
  354. {
  355. DWORD dwUsedTime = timeGetTime() - ptm->dwStartTime; // Compute time used
  356. DWORD dwProjected = (ptm->dwRange / ptm->dwCount) * dwUsedTime; // Project Time to complete
  357. DWORD dwProjRemain = dwProjected - dwUsedTime; // Compute projected remaining time
  358. if (dwProjRemain >= 1500) // If it looks like it's going to take a while, put up the meter
  359. {
  360. DWORD dwNumJumps = ptm->dwCount / ptm->dwJump;
  361. DWORD dwJumpTime = dwUsedTime / dwNumJumps;
  362. if (dwJumpTime > 200) // To make sure the meter moves smoothly, re-compute jump count
  363. {
  364. ptm->dwJump = (ptm->dwJump / ((dwJumpTime / 200) + 1)) + 1;
  365. }
  366. ptm->dwShowCount = ptm->dwCount;
  367. SendDlgItemMessage( ptm->hMeter, IDC_PROGRESSMETER, PBM_SETRANGE, 0, MAKELPARAM(0, ptm->dwRange - ptm->dwShowCount));
  368. SendDlgItemMessage( ptm->hMeter, IDC_PROGRESSMETER, PBM_SETPOS, (WPARAM) 0, 0);
  369. ShowWindow(ptm->hMeter,SW_SHOWNORMAL);
  370. UpdateWindow(ptm->hMeter);
  371. ptm->fShowing = TRUE;
  372. }
  373. }
  374. }
  375. }
  376. }
  377. STDMETHODIMP_(void) CCDData::DestroyMeter(LPTIMEDMETER ptm)
  378. {
  379. if (ptm && ptm->hMeter)
  380. {
  381. DestroyWindow(ptm->hMeter);
  382. SetForegroundWindow(ptm->hParent);
  383. memset(ptm, 0, sizeof(LPTIMEDMETER));
  384. }
  385. }
  386. STDMETHODIMP_(void) CCDData::InitDatabase(HSTMT *hstmt)
  387. {
  388. m_pSQL->ExecDirect(hstmt[0], (UCHAR *) TEXT("drop table Titles"), SQL_NTS);
  389. m_pSQL->ExecDirect(hstmt[1], (UCHAR *) TEXT("drop table Tracks"), SQL_NTS);
  390. m_pSQL->ExecDirect(hstmt[2], (UCHAR *) TEXT("drop table Menus"), SQL_NTS);
  391. m_pSQL->ExecDirect(hstmt[3], (UCHAR *) TEXT("drop table Batch"), SQL_NTS);
  392. m_pSQL->ExecDirect(hstmt[0], (UCHAR *) gszTitlesCreate, SQL_NTS);
  393. m_pSQL->ExecDirect(hstmt[1], (UCHAR *) gszTracksCreate, SQL_NTS);
  394. m_pSQL->ExecDirect(hstmt[2], (UCHAR *) gszMenusCreate, SQL_NTS);
  395. m_pSQL->ExecDirect(hstmt[3], (UCHAR *) gszBatchCreate, SQL_NTS);
  396. m_pSQL->FreeStmt(hstmt[0], SQL_CLOSE);
  397. m_pSQL->FreeStmt(hstmt[1], SQL_CLOSE);
  398. m_pSQL->FreeStmt(hstmt[2], SQL_CLOSE);
  399. m_pSQL->FreeStmt(hstmt[3], SQL_CLOSE);
  400. }
  401. STDMETHODIMP_(void) CCDData::SetCursors(HSTMT *hstmt)
  402. {
  403. for (DWORD dwIndex = 0; dwIndex < NUMTABLES; dwIndex++)
  404. {
  405. m_pSQL->SetStmtOption(hstmt[dwIndex], SQL_CONCURRENCY, SQL_CONCUR_VALUES);
  406. m_pSQL->SetStmtOption(hstmt[dwIndex], SQL_CURSOR_TYPE, SQL_CURSOR_KEYSET_DRIVEN);
  407. m_pSQL->SetStmtOption(hstmt[dwIndex], SQL_ROWSET_SIZE, ROWSET);
  408. }
  409. }
  410. STDMETHODIMP_(void) CCDData::InitCBTable(LPBOUND pbd)
  411. {
  412. memcpy(pbd->cbt.cbTitles, gcbTitles, sizeof(gcbTitles));
  413. memcpy(pbd->cbt.cbTracks, gcbTracks, sizeof(gcbTracks));
  414. memcpy(pbd->cbt.cbMenus, gcbMenus, sizeof(gcbMenus));
  415. memcpy(pbd->cbt.cbBatch, gcbBatch, sizeof(gcbBatch));
  416. }
  417. STDMETHODIMP_(void) CCDData::BindTitles(HSTMT *hstmt, LPBOUND pbd)
  418. {
  419. m_pSQL->BindCol(hstmt[0], 1, SQL_C_ULONG, &(pbd->CDTitle.dwTitleID), sizeof(pbd->CDTitle.dwTitleID), &pbd->cbt.cbTitles[0]);
  420. m_pSQL->BindCol(hstmt[0], 2, SQL_C_WCHAR, pbd->CDTitle.szArtist, sizeof(pbd->CDTitle.szArtist), &pbd->cbt.cbTitles[1]);
  421. m_pSQL->BindCol(hstmt[0], 3, SQL_C_WCHAR, pbd->CDTitle.szTitle, sizeof(pbd->CDTitle.szTitle), &pbd->cbt.cbTitles[2]);
  422. m_pSQL->BindCol(hstmt[0], 4, SQL_C_WCHAR, pbd->CDTitle.szCopyright, sizeof(pbd->CDTitle.szCopyright), &pbd->cbt.cbTitles[3]);
  423. m_pSQL->BindCol(hstmt[0], 5, SQL_C_WCHAR, pbd->CDTitle.szLabel, sizeof(pbd->CDTitle.szLabel), &pbd->cbt.cbTitles[4]);
  424. m_pSQL->BindCol(hstmt[0], 6, SQL_C_WCHAR, pbd->CDTitle.szDate, sizeof(pbd->CDTitle.szDate), &pbd->cbt.cbTitles[5]);
  425. m_pSQL->BindCol(hstmt[0], 7, SQL_C_ULONG, &(pbd->CDTitle.dwNumTracks), sizeof(pbd->CDTitle.dwNumTracks), &pbd->cbt.cbTitles[6]);
  426. m_pSQL->BindCol(hstmt[0], 8, SQL_C_ULONG, &(pbd->CDTitle.dwNumMenus), sizeof(pbd->CDTitle.dwNumMenus), &pbd->cbt.cbTitles[7]);
  427. m_pSQL->BindCol(hstmt[0], 9, SQL_C_WCHAR, pbd->szPlayList, sizeof(pbd->szPlayList), &pbd->cbt.cbTitles[8]);
  428. m_pSQL->BindCol(hstmt[0], 10, SQL_C_WCHAR, pbd->szQuery, sizeof(pbd->szQuery), &pbd->cbt.cbTitles[9]);
  429. }
  430. STDMETHODIMP_(void) CCDData::BindTracks(HSTMT *hstmt, LPBOUND pbd)
  431. {
  432. m_pSQL->BindCol(hstmt[1], 1, SQL_C_ULONG, &(pbd->CDTitle.dwTitleID), sizeof(pbd->CDTitle.dwTitleID), &pbd->cbt.cbTracks[0]);
  433. m_pSQL->BindCol(hstmt[1], 2, SQL_C_ULONG, &(pbd->dwTrackID), sizeof(pbd->dwTrackID), &pbd->cbt.cbTracks[1]);
  434. m_pSQL->BindCol(hstmt[1], 3, SQL_C_WCHAR, pbd->CDTrack.szName, sizeof(pbd->CDTrack.szName), &pbd->cbt.cbTracks[2]);
  435. }
  436. STDMETHODIMP_(void) CCDData::BindMenus(HSTMT *hstmt, LPBOUND pbd)
  437. {
  438. m_pSQL->BindCol(hstmt[2], 1, SQL_C_ULONG, &(pbd->CDTitle.dwTitleID), sizeof(pbd->CDTitle.dwTitleID), &pbd->cbt.cbMenus[0]);
  439. m_pSQL->BindCol(hstmt[2], 2, SQL_C_ULONG, &(pbd->dwMenuID), sizeof(pbd->dwMenuID), &pbd->cbt.cbMenus[1]);
  440. m_pSQL->BindCol(hstmt[2], 3, SQL_C_WCHAR, pbd->CDMenu.szMenuText, sizeof(pbd->CDMenu.szMenuText), &pbd->cbt.cbMenus[2]);
  441. m_pSQL->BindCol(hstmt[2], 4, SQL_C_WCHAR, pbd->szQuery, sizeof(pbd->szQuery), &pbd->cbt.cbMenus[3]);
  442. }
  443. STDMETHODIMP_(void) CCDData::BindBatch(HSTMT *hstmt, LPBOUND pbd)
  444. {
  445. m_pSQL->BindCol(hstmt[3], 1, SQL_C_ULONG, &(pbd->CDTitle.dwTitleID), sizeof(pbd->CDTitle.dwTitleID), &pbd->cbt.cbBatch[0]);
  446. m_pSQL->BindCol(hstmt[3], 2, SQL_C_ULONG, &(pbd->CDTitle.dwNumTracks), sizeof(pbd->CDTitle.dwNumTracks), &pbd->cbt.cbBatch[1]);
  447. m_pSQL->BindCol(hstmt[3], 3, SQL_C_WCHAR, pbd->szQuery, sizeof(pbd->szQuery), &pbd->cbt.cbBatch[2]);
  448. }
  449. STDMETHODIMP_(void) CCDData::SetBindings(HSTMT *hstmt, LPBOUND pbd)
  450. {
  451. BindTitles(hstmt,pbd);
  452. BindTracks(hstmt,pbd);
  453. BindMenus(hstmt,pbd);
  454. BindBatch(hstmt,pbd);
  455. }
  456. STDMETHODIMP_(void) CCDData::ReportError(LPBOUND pbd, HSTMT hstmt)
  457. {
  458. #ifdef DEBUG
  459. UCHAR state[255];
  460. SDWORD dwErr;
  461. UCHAR szErr[SQL_MAX_MESSAGE_LENGTH];
  462. SWORD cbErr;
  463. m_pSQL->Error(pbd->henv, pbd->hdbc, hstmt, state, &dwErr, szErr, SQL_MAX_MESSAGE_LENGTH, &cbErr);
  464. OutputDebugString((TCHAR *) szErr);
  465. if (szErr[0] != TEXT('\0'))
  466. {
  467. OutputDebugString(TEXT("\n"));
  468. }
  469. #endif
  470. }
  471. STDMETHODIMP_(RETCODE) CCDData::AllocStmt(HDBC hdbc, HSTMT *hstmt)
  472. {
  473. RETCODE rc = SQL_SUCCESS;
  474. DWORD dwIndex;
  475. for (dwIndex = 0; dwIndex < NUMTABLES; dwIndex++)
  476. {
  477. hstmt[dwIndex] = NULL;
  478. }
  479. for (dwIndex = 0; dwIndex < NUMTABLES; dwIndex++)
  480. {
  481. rc = m_pSQL->AllocStmt(hdbc, &hstmt[dwIndex]);
  482. if (rc != SQL_SUCCESS)
  483. {
  484. break;
  485. }
  486. }
  487. return(rc);
  488. }
  489. STDMETHODIMP_(void) CCDData::FreeStmt(HSTMT *hstmt)
  490. {
  491. RETCODE rc = SQL_SUCCESS;
  492. DWORD dwIndex;
  493. for (dwIndex = 0; dwIndex < NUMTABLES; dwIndex++)
  494. {
  495. if (hstmt[dwIndex] != NULL)
  496. {
  497. m_pSQL->FreeStmt(hstmt[dwIndex], SQL_DROP);
  498. hstmt[dwIndex] = NULL;
  499. }
  500. }
  501. }
  502. STDMETHODIMP_(void) CCDData::CreateDatabase(void)
  503. {
  504. HENV henv;
  505. HDBC hdbc;
  506. HSTMT hstmt[NUMTABLES];
  507. TCHAR szWinDir[MAX_PATH];
  508. TCHAR szCreateAttr[MAX_PATH];
  509. TCHAR szDSNAttr[MAX_PATH];
  510. if (GetAppDataDir(szWinDir, sizeof(szWinDir)/sizeof(TCHAR)) != 0)
  511. {
  512. wsprintf(szCreateAttr, gszDSNCreate, szWinDir, TEXT('\0'));
  513. wsprintf(szDSNAttr, gszDSNAttr, TEXT('\0'), szWinDir, TEXT('\0'), TEXT('\0'), TEXT('\0'));
  514. if (m_pSQL->ConfigDataSource(NULL, ODBC_ADD_DSN, gszDriverName, szCreateAttr))
  515. {
  516. if (m_pSQL->ConfigDataSource(NULL, ODBC_ADD_DSN, gszDriverName, szDSNAttr))
  517. {
  518. if (m_pSQL->AllocEnv(&henv) == SQL_SUCCESS)
  519. {
  520. if (m_pSQL->AllocConnect(henv, &hdbc) == SQL_SUCCESS)
  521. {
  522. if (m_pSQL->Connect(hdbc, (UCHAR *) gszDSN, SQL_NTS, NULL, 0, NULL, 0) == SQL_SUCCESS)
  523. {
  524. if (AllocStmt(hdbc, hstmt) == SQL_SUCCESS)
  525. {
  526. InitDatabase(hstmt);
  527. }
  528. FreeStmt(hstmt);
  529. }
  530. m_pSQL->Disconnect(hdbc);
  531. }
  532. m_pSQL->FreeConnect(hdbc);
  533. }
  534. m_pSQL->FreeEnv(henv);
  535. }
  536. }
  537. }
  538. }
  539. STDMETHODIMP CCDData::CheckDatabase(HWND hWnd)
  540. {
  541. HRESULT hr = S_OK;
  542. GetSQLPtr(FALSE);
  543. if (!m_pSQL)
  544. {
  545. if (!m_fToldUser)
  546. {
  547. TCHAR szTitle[255];
  548. TCHAR szCaption[255];
  549. LoadString(g_dllInst, IDS_ERROR_NO_ODBC, szTitle, sizeof(szTitle)/sizeof(TCHAR));
  550. LoadString(g_dllInst, IDS_ERROR_SETUP, szCaption, sizeof(szTitle)/sizeof(TCHAR));
  551. MessageBox(hWnd, szTitle, szCaption, MB_OK | MB_ICONEXCLAMATION);
  552. m_fToldUser = TRUE;
  553. }
  554. hr = E_FAIL;
  555. }
  556. return(hr);
  557. }
  558. //finds the dir for allowing roaming profiles
  559. STDMETHODIMP_(DWORD) CCDData::GetAppDataDir(TCHAR* pstrDir, DWORD cchSize)
  560. {
  561. DWORD dwRet = 0;
  562. /*
  563. TCHAR szDir[MAX_PATH] = TEXT("%userprofile%\\Application Data\\Microsoft\\DeluxeCD");
  564. dwRet = ExpandEnvironmentStrings(szDir,pstrDir,cchSize);
  565. if (dwRet > 0)
  566. {
  567. CreateDirectory(pstrDir,NULL);
  568. //shorten the pathname, because ODBC can't handle spaces
  569. _tcscpy(szDir,pstrDir);
  570. dwRet = GetShortPathName(szDir,pstrDir,cchSize);
  571. }
  572. */
  573. dwRet = GetWindowsDirectory(pstrDir,cchSize);
  574. return (dwRet);
  575. }
  576. STDMETHODIMP CCDData::Initialize(HWND hWnd)
  577. {
  578. TCHAR *pEntries = NULL;
  579. HRESULT hr = S_OK;
  580. DWORD dwCount;
  581. UDWORD row[NUMTABLES];
  582. UWORD rgfRowStat[NUMTABLES][ROWSET];
  583. TCHAR szWinDir[MAX_PATH];
  584. TCHAR szCreateAttr[MAX_PATH];
  585. TIMEDMETER tm;
  586. if (SUCCEEDED(GetSQLPtr(TRUE)))
  587. {
  588. if (GetAppDataDir(szWinDir, sizeof(szWinDir)/sizeof(TCHAR)) != 0)
  589. {
  590. wsprintf(szCreateAttr, gszDSNCreate, szWinDir, TEXT('\0'));
  591. if (m_pSQL->ConfigDataSource(NULL, ODBC_ADD_DSN, gszDriverName, szCreateAttr)) // If this fails, we assume we've already imported the file
  592. {
  593. hr = GetUnknownString(&pEntries, NULL, NULL, SECTION_BUFFER);
  594. if (SUCCEEDED(hr))
  595. {
  596. dwCount = ImportCount(pEntries);
  597. CreateMeter(&tm, hWnd, dwCount, 5, IDS_IMPORTING);
  598. OpenDatabase(TRUE,hWnd);
  599. if (m_henv)
  600. {
  601. TCHAR *szDiscID = pEntries;
  602. DWORD dwIndex;
  603. memset(&m_bd, 0, sizeof(m_bd));
  604. m_bd.henv = m_henv;
  605. m_bd.hdbc = m_hdbc;
  606. InitDatabase(m_hstmt);
  607. InitCBTable(&m_bd);
  608. SetCursors( m_hstmt );
  609. SetBindings( m_hstmt, &m_bd);
  610. m_pSQL->SetConnectOption(m_hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
  611. m_pSQL->ExecDirect(m_hstmt[0], (UCHAR *) TEXT("select * from Titles"), SQL_NTS);
  612. m_pSQL->ExecDirect(m_hstmt[1], (UCHAR *) TEXT("select * from Tracks"), SQL_NTS);
  613. m_pSQL->ExecDirect(m_hstmt[2], (UCHAR *) TEXT("select * from Menus"), SQL_NTS);
  614. for (dwIndex = 0; dwIndex < NUMTABLES; dwIndex++)
  615. {
  616. m_pSQL->ExtendedFetch(m_hstmt[dwIndex], SQL_FETCH_FIRST, 1, &row[dwIndex], rgfRowStat[dwIndex]);
  617. }
  618. ImportDatabase(&tm, m_hstmt, szDiscID);
  619. m_pSQL->Transact(SQL_NULL_HENV, m_hdbc, SQL_COMMIT);
  620. for (dwIndex = 0; dwIndex < NUMTABLES; dwIndex++)
  621. {
  622. m_pSQL->FreeStmt(m_hstmt[dwIndex], SQL_CLOSE);
  623. }
  624. m_pSQL->ExecDirect(m_hstmt[0], (UCHAR *) TEXT("create index TitleIDx on Titles(TitleID)"), SQL_NTS);
  625. m_pSQL->ExecDirect(m_hstmt[1], (UCHAR *) TEXT("create index TitleIDx on Tracks(TitleID)"), SQL_NTS);
  626. m_pSQL->ExecDirect(m_hstmt[2], (UCHAR *) TEXT("create index TitleIDx on Menus(TitleID)"), SQL_NTS);
  627. m_pSQL->Transact(SQL_NULL_HENV, m_hdbc, SQL_COMMIT);
  628. m_pSQL->SetConnectOption(m_hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
  629. CloseDatabase();
  630. }
  631. DestroyMeter(&tm);
  632. }
  633. if (pEntries)
  634. {
  635. delete pEntries;
  636. }
  637. }
  638. hr = OpenDatabase(FALSE,hWnd); // We either already have a database or we just created one, open it. (If we didn't import OpenDatabase will create new one
  639. }
  640. }
  641. return(hr);
  642. }
  643. STDMETHODIMP CCDData::ConnectToDatabase(WORD fRequest)
  644. {
  645. HRESULT hr = E_FAIL;
  646. TCHAR szWinDir[MAX_PATH];
  647. TCHAR szDSNAttr[MAX_PATH];
  648. if (GetAppDataDir(szWinDir, sizeof(szWinDir)/sizeof(TCHAR)) != 0)
  649. {
  650. wsprintf(szDSNAttr, gszDSNAttr, TEXT('\0'), szWinDir, TEXT('\0'), TEXT('\0'), TEXT('\0'));
  651. if (m_pSQL->ConfigDataSource(NULL, fRequest, gszDriverName, szDSNAttr))
  652. {
  653. if (m_pSQL->AllocEnv(&m_henv) == SQL_SUCCESS)
  654. {
  655. if (m_pSQL->AllocConnect(m_henv, &m_hdbc) == SQL_SUCCESS)
  656. {
  657. if (m_pSQL->Connect(m_hdbc, (UCHAR *) gszDSN, SQL_NTS, NULL, 0, NULL, 0) == SQL_SUCCESS)
  658. {
  659. if (AllocStmt(m_hdbc, m_hstmt) == SQL_SUCCESS)
  660. {
  661. hr = S_OK;
  662. }
  663. }
  664. }
  665. }
  666. }
  667. }
  668. return(hr);
  669. }
  670. STDMETHODIMP CCDData::OpenDatabase(BOOL fCreate, HWND hWnd)
  671. {
  672. HRESULT hr = E_FAIL;
  673. m_henv = NULL;
  674. m_hdbc = NULL;
  675. for (DWORD dwIndex = 0; dwIndex < NUMTABLES; dwIndex++)
  676. {
  677. m_hstmt[dwIndex] = NULL;
  678. }
  679. hr = ConnectToDatabase(ODBC_ADD_DSN);
  680. if (FAILED(hr)) // Lets try creating the database
  681. {
  682. CreateDatabase();
  683. hr = ConnectToDatabase(ODBC_CONFIG_DSN);
  684. }
  685. else
  686. {
  687. //only do this if connection to database succeeded right off the bat,
  688. //because if we just created a new one, it is in the right format already.
  689. if (IsOldFormat())
  690. {
  691. hr = UpgradeDatabase(hWnd);
  692. }
  693. }
  694. if (FAILED(hr))
  695. {
  696. CloseDatabase();
  697. }
  698. return (hr);
  699. }
  700. STDMETHODIMP_(void) CCDData::CloseDatabase(void)
  701. {
  702. if (m_pSQL)
  703. {
  704. FreeStmt(m_hstmt);
  705. if (m_hdbc)
  706. {
  707. m_pSQL->Disconnect(m_hdbc);
  708. m_pSQL->FreeConnect(m_hdbc);
  709. }
  710. if (m_henv)
  711. {
  712. m_pSQL->FreeEnv(m_henv);
  713. }
  714. }
  715. }
  716. STDMETHODIMP_(DWORD) CCDData::GetNumRows(UCHAR *szDSN)
  717. {
  718. HSTMT hstmt;
  719. DWORD dwCount = 0;
  720. SWORD Type,Cardinality;
  721. SDWORD cbCardinality = 0, cbType = 0;
  722. RETCODE rc;
  723. if (m_pSQL->AllocStmt(m_hdbc, &hstmt) == SQL_SUCCESS)
  724. {
  725. if (m_pSQL->Statistics(hstmt, NULL, 0, NULL, 0, szDSN, SQL_NTS, SQL_INDEX_ALL, SQL_ENSURE) == SQL_SUCCESS)
  726. {
  727. rc = m_pSQL->BindCol(hstmt, 7, SQL_C_SSHORT, &Type, sizeof(Type), &cbType);
  728. rc = m_pSQL->BindCol(hstmt, 11, SQL_C_SSHORT, &Cardinality, sizeof(Cardinality), &cbCardinality);
  729. if (rc != SQL_SUCCESS)
  730. {
  731. ReportError(&m_bd, hstmt);
  732. }
  733. while (rc == SQL_SUCCESS)
  734. {
  735. rc = m_pSQL->Fetch(hstmt);
  736. if (rc == SQL_SUCCESS)
  737. {
  738. if (Type == SQL_TABLE_STAT)
  739. {
  740. dwCount = (DWORD) Cardinality;
  741. break;
  742. }
  743. }
  744. }
  745. }
  746. m_pSQL->FreeStmt(hstmt, SQL_DROP);
  747. }
  748. return(dwCount);
  749. }
  750. STDMETHODIMP CCDData::ExtractTitle(LPCDTITLE *ppCDTitle)
  751. {
  752. HRESULT hr;
  753. LPCDTITLE pCDTitle = NULL;
  754. m_bd.CDTitle.fLoaded = FALSE;
  755. hr = NewTitle(&pCDTitle, m_bd.CDTitle.dwTitleID, m_bd.CDTitle.dwNumTracks, m_bd.CDTitle.dwNumMenus);
  756. if (SUCCEEDED(hr))
  757. {
  758. DWORD dwTrack = 0;
  759. DWORD dwMenu = 0;
  760. m_bd.CDTitle.pTrackTable = pCDTitle->pTrackTable;
  761. m_bd.CDTitle.pMenuTable = pCDTitle->pMenuTable;
  762. m_bd.CDTitle.pPlayList = pCDTitle->pPlayList;
  763. memcpy(pCDTitle,&m_bd.CDTitle,sizeof(m_bd.CDTitle));
  764. memset(&m_bd.CDTitle, 0, sizeof(m_bd.CDTitle));
  765. DWORD dwSize = lstrlen(m_bd.szQuery) + 1;
  766. if (dwSize)
  767. {
  768. pCDTitle->szTitleQuery = new(TCHAR[dwSize]);
  769. if (pCDTitle->szTitleQuery)
  770. {
  771. lstrcpy(pCDTitle->szTitleQuery, m_bd.szQuery);
  772. }
  773. }
  774. pCDTitle->dwNumPlay = lstrlen(m_bd.szPlayList) >> 1; // Null terminated, two digits per entry (two chars) thus divide by 2
  775. if (pCDTitle->dwNumPlay)
  776. {
  777. pCDTitle->dwNumPlay = min(pCDTitle->dwNumPlay, MAXNUMPLAY);
  778. pCDTitle->pPlayList = new(WORD[pCDTitle->dwNumPlay]);
  779. if (pCDTitle->pPlayList == NULL)
  780. {
  781. pCDTitle->dwNumPlay = 0;
  782. }
  783. else
  784. {
  785. TCHAR *pText = m_bd.szPlayList;
  786. LPWORD pNum = pCDTitle->pPlayList;
  787. DWORD dwIndex = 0;
  788. TCHAR szNum[3];
  789. int iNum;
  790. szNum[2] = TEXT('\0');
  791. for (dwIndex = 0; dwIndex < pCDTitle->dwNumPlay; dwIndex++, pNum++)
  792. {
  793. szNum[0] = *pText++;
  794. szNum[1] = *pText++;
  795. _stscanf(szNum, TEXT("%02x"), &iNum);
  796. *pNum = (WORD) iNum;
  797. }
  798. }
  799. }
  800. }
  801. if (SUCCEEDED(hr) && ppCDTitle)
  802. {
  803. *ppCDTitle = pCDTitle;
  804. }
  805. else if (pCDTitle)
  806. {
  807. DestroyTitle(pCDTitle);
  808. }
  809. return(hr);
  810. }
  811. STDMETHODIMP_(LPCDTITLE) CCDData::FindTitle(LPCDTITLE pCDTitle, DWORD dwTitleID)
  812. {
  813. while (pCDTitle)
  814. {
  815. if (pCDTitle->dwTitleID == dwTitleID)
  816. {
  817. break;
  818. }
  819. pCDTitle = pCDTitle->pNext;
  820. }
  821. return(pCDTitle);
  822. }
  823. STDMETHODIMP CCDData::ExtractTitles(LPCDTITLE *ppCDTitleList, HWND hWnd)
  824. {
  825. HRESULT hr = S_OK;
  826. LPCDTITLE pCDTitle = NULL;;
  827. TIMEDMETER tm;
  828. InitCBTable(&m_bd);
  829. SetCursors(m_hstmt);
  830. SetBindings(m_hstmt, &m_bd);
  831. if (ppCDTitleList == NULL || m_henv == NULL)
  832. {
  833. hr = E_INVALIDARG;
  834. }
  835. else
  836. {
  837. RETCODE rc;
  838. DWORD dwCount = GetNumRows((UCHAR *) gszTitleTable) + GetNumRows((UCHAR *) gszTrackTable) + GetNumRows((UCHAR *) gszMenuTable);
  839. CreateMeter(&tm, hWnd, dwCount, 100, 0);
  840. dwCount = 0;
  841. rc = m_pSQL->ExecDirect(m_hstmt[0], (UCHAR *) TEXT("select * from Titles"), SQL_NTS);
  842. if (rc == SQL_SUCCESS)
  843. {
  844. m_bd.szQuery[0] = TEXT('\0');
  845. while (m_pSQL->Fetch(m_hstmt[0]) == SQL_SUCCESS)
  846. {
  847. hr = ExtractTitle(&pCDTitle);
  848. if (SUCCEEDED(hr))
  849. {
  850. AddTitle(ppCDTitleList, pCDTitle);
  851. UpdateMeter(&tm);
  852. }
  853. m_bd.szQuery[0] = TEXT('\0');
  854. }
  855. if (*ppCDTitleList)
  856. {
  857. hr = S_OK;
  858. }
  859. m_pSQL->FreeStmt(m_hstmt[0], SQL_CLOSE);
  860. m_pSQL->ExecDirect(m_hstmt[1], (UCHAR *) TEXT("select * from Tracks"), SQL_NTS);
  861. pCDTitle = NULL;
  862. while (m_pSQL->Fetch(m_hstmt[1]) == SQL_SUCCESS)
  863. {
  864. if (pCDTitle == NULL || pCDTitle->dwTitleID != m_bd.CDTitle.dwTitleID)
  865. {
  866. pCDTitle = FindTitle(*ppCDTitleList, m_bd.CDTitle.dwTitleID);
  867. }
  868. if (pCDTitle)
  869. {
  870. if (m_bd.dwTrackID < pCDTitle->dwNumTracks)
  871. {
  872. memcpy(&(pCDTitle->pTrackTable[m_bd.dwTrackID]), &(m_bd.CDTrack), sizeof(m_bd.CDTrack));
  873. UpdateMeter(&tm);
  874. }
  875. }
  876. }
  877. m_pSQL->FreeStmt(m_hstmt[1], SQL_CLOSE);
  878. m_pSQL->ExecDirect(m_hstmt[2], (UCHAR *) TEXT("select * from Menus"), SQL_NTS);
  879. pCDTitle = NULL;
  880. m_bd.szQuery[0] = TEXT('\0');
  881. while (m_pSQL->Fetch(m_hstmt[2]) == SQL_SUCCESS)
  882. {
  883. if (pCDTitle == NULL || pCDTitle->dwTitleID != m_bd.CDTitle.dwTitleID)
  884. {
  885. pCDTitle = FindTitle(*ppCDTitleList, m_bd.CDTitle.dwTitleID);
  886. }
  887. if (pCDTitle)
  888. {
  889. if (m_bd.dwMenuID < pCDTitle->dwNumMenus)
  890. {
  891. LPCDMENU pCDMenu = &(pCDTitle->pMenuTable[m_bd.dwMenuID]);
  892. TCHAR *szMenuQuery;
  893. SetMenuQuery(pCDMenu, m_bd.szQuery);
  894. szMenuQuery = pCDMenu->szMenuQuery;
  895. memcpy(pCDMenu, &(m_bd.CDMenu), sizeof(m_bd.CDMenu));
  896. pCDMenu->szMenuQuery = szMenuQuery;
  897. m_bd.szQuery[0] = TEXT('\0');
  898. UpdateMeter(&tm);
  899. }
  900. }
  901. }
  902. m_pSQL->FreeStmt(m_hstmt[2], SQL_CLOSE);
  903. }
  904. DestroyMeter(&tm);
  905. }
  906. return(hr);
  907. }
  908. STDMETHODIMP CCDData::ExtractSingleTitle(LPCDTITLE *ppCDTitle, DWORD dwTitleID)
  909. {
  910. HRESULT hr = S_OK;
  911. LPCDTITLE pCDTitle = NULL;;
  912. InitCBTable(&m_bd);
  913. SetCursors(m_hstmt);
  914. SetBindings( m_hstmt, &m_bd);
  915. if (ppCDTitle == NULL || m_henv == NULL)
  916. {
  917. hr = E_INVALIDARG;
  918. }
  919. else
  920. {
  921. RETCODE rc;
  922. UCHAR szQuery[MAX_PATH];
  923. wsprintf((TCHAR *) szQuery, TEXT("select * from Titles where TitleID = %d"), dwTitleID);
  924. rc = m_pSQL->ExecDirect(m_hstmt[0], szQuery, SQL_NTS);
  925. if (rc != SQL_SUCCESS)
  926. {
  927. hr = E_FAIL;
  928. }
  929. else
  930. {
  931. if (m_pSQL->Fetch(m_hstmt[0]) == SQL_SUCCESS)
  932. {
  933. hr = ExtractTitle(&pCDTitle);
  934. }
  935. else
  936. {
  937. hr = E_FAIL;
  938. }
  939. m_pSQL->FreeStmt(m_hstmt[0], SQL_CLOSE);
  940. if (SUCCEEDED(hr))
  941. {
  942. wsprintf((TCHAR *) szQuery, TEXT("select * from Tracks where TitleID = %d"), dwTitleID);
  943. m_pSQL->ExecDirect(m_hstmt[1], szQuery, SQL_NTS);
  944. while (m_pSQL->Fetch(m_hstmt[1]) == SQL_SUCCESS)
  945. {
  946. if (m_bd.dwTrackID < pCDTitle->dwNumTracks)
  947. {
  948. memcpy(&(pCDTitle->pTrackTable[m_bd.dwTrackID]), &(m_bd.CDTrack), sizeof(m_bd.CDTrack));
  949. }
  950. }
  951. m_pSQL->FreeStmt(m_hstmt[1], SQL_CLOSE);
  952. wsprintf((TCHAR *) szQuery, TEXT("select * from Menus where TitleID = %d"), dwTitleID);
  953. m_pSQL->ExecDirect(m_hstmt[2], szQuery, SQL_NTS);
  954. while (m_pSQL->Fetch(m_hstmt[2]) == SQL_SUCCESS)
  955. {
  956. if (m_bd.dwMenuID < pCDTitle->dwNumMenus)
  957. {
  958. LPCDMENU pCDMenu = &(pCDTitle->pMenuTable[m_bd.dwMenuID]);
  959. TCHAR *szMenuQuery;
  960. SetMenuQuery(pCDMenu, m_bd.szQuery);
  961. szMenuQuery = pCDMenu->szMenuQuery;
  962. memcpy(pCDMenu, &(m_bd.CDMenu), sizeof(m_bd.CDMenu));
  963. pCDMenu->szMenuQuery = szMenuQuery;
  964. m_bd.szQuery[0] = TEXT('\0');
  965. }
  966. }
  967. m_pSQL->FreeStmt(m_hstmt[2], SQL_CLOSE);
  968. }
  969. } //end else main query successful
  970. } //end else args ok
  971. if (SUCCEEDED(hr))
  972. {
  973. *ppCDTitle = pCDTitle;
  974. }
  975. return(hr);
  976. }
  977. STDMETHODIMP_(BOOL) CCDData::QueryDatabase(DWORD dwTitleID, const TCHAR *szTable)
  978. {
  979. BOOL fResult = FALSE;
  980. RETCODE rc;
  981. UCHAR szQuery[MAX_PATH];
  982. HSTMT hstmt;
  983. if (m_pSQL->AllocStmt(m_hdbc, &hstmt) == SQL_SUCCESS)
  984. {
  985. wsprintf((TCHAR *) szQuery, TEXT("select * from %s where TitleID = %d"), szTable, dwTitleID);
  986. rc = m_pSQL->ExecDirect(hstmt, szQuery, SQL_NTS);
  987. if (rc == SQL_SUCCESS)
  988. {
  989. if (m_pSQL->Fetch(hstmt) == SQL_SUCCESS)
  990. {
  991. fResult = TRUE;
  992. }
  993. }
  994. m_pSQL->FreeStmt(hstmt, SQL_DROP);
  995. }
  996. return (fResult);
  997. }
  998. STDMETHODIMP_(BOOL) CCDData::QueryTitle(DWORD dwTitleID)
  999. {
  1000. BOOL fResult = FALSE;
  1001. LPCDTITLE pCDTitle;
  1002. Enter();
  1003. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1004. {
  1005. if (m_pTitleList == NULL) // Database Not in memory, just query database directly
  1006. {
  1007. fResult = QueryDatabase(dwTitleID, gszTitleTable);
  1008. }
  1009. else // Database is in memory, just look here.
  1010. {
  1011. pCDTitle = m_pTitleList;
  1012. while (pCDTitle)
  1013. {
  1014. if (pCDTitle->dwTitleID == dwTitleID)
  1015. {
  1016. if (!pCDTitle->fRemove)
  1017. {
  1018. fResult = TRUE;
  1019. }
  1020. break;
  1021. }
  1022. pCDTitle = pCDTitle->pNext;
  1023. }
  1024. }
  1025. }
  1026. Leave();
  1027. return(fResult);
  1028. }
  1029. STDMETHODIMP CCDData::LockTitle(LPCDTITLE *ppCDTitle, DWORD dwTitleID)
  1030. {
  1031. HRESULT hr = E_INVALIDARG;
  1032. Enter();
  1033. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1034. {
  1035. if (ppCDTitle)
  1036. {
  1037. if (m_pTitleList == NULL) // Database Not in memory, load explicitly
  1038. {
  1039. if (SUCCEEDED(ExtractSingleTitle(ppCDTitle, dwTitleID)))
  1040. {
  1041. (*ppCDTitle)->fLoaded = TRUE;
  1042. (*ppCDTitle)->dwLockCnt = 1;
  1043. hr = S_OK;
  1044. }
  1045. }
  1046. else // Database is in memory, just look here.
  1047. {
  1048. LPCDTITLE pCDTitle;
  1049. pCDTitle = m_pTitleList;
  1050. while (pCDTitle)
  1051. {
  1052. if (pCDTitle->dwTitleID == dwTitleID)
  1053. {
  1054. *ppCDTitle = pCDTitle;
  1055. pCDTitle->fLoaded = FALSE;
  1056. pCDTitle->dwLockCnt++;
  1057. hr = S_OK;
  1058. break;
  1059. }
  1060. pCDTitle = pCDTitle->pNext;
  1061. }
  1062. }
  1063. }
  1064. }
  1065. Leave();
  1066. return(hr);
  1067. }
  1068. STDMETHODIMP_(void) CCDData::UnlockTitle(LPCDTITLE pCDTitle, BOOL fPresist)
  1069. {
  1070. Enter();
  1071. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1072. {
  1073. if (pCDTitle)
  1074. {
  1075. if (fPresist) // They either made a new one, or made changes
  1076. {
  1077. DBSaveTitle(pCDTitle); // write it to database
  1078. }
  1079. if (pCDTitle->fLoaded) // This was NOT pulled from our database (Either locked while we didn't have the database, or was created.
  1080. {
  1081. pCDTitle->dwLockCnt--; // they are unlocking
  1082. if (fPresist && m_dwLoadCnt) // This is a new item, lets add it to load database
  1083. {
  1084. AddTitle(&m_pTitleList, pCDTitle); // Insert into the loaded databased
  1085. }
  1086. else if (pCDTitle->dwLockCnt == 0) // Not being saved and not in database, so nuke it
  1087. {
  1088. DestroyTitle(pCDTitle);
  1089. }
  1090. }
  1091. else // This title was pulled from our database, so just dec the ref
  1092. {
  1093. pCDTitle->dwLockCnt--;
  1094. }
  1095. }
  1096. }
  1097. Leave();
  1098. }
  1099. BOOL CALLBACK CCDData::MeterHandler(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  1100. {
  1101. BOOL fReturnVal = TRUE;
  1102. switch (msg)
  1103. {
  1104. default:
  1105. fReturnVal = FALSE;
  1106. break;
  1107. case WM_INITDIALOG:
  1108. {
  1109. fReturnVal = TRUE;
  1110. }
  1111. break;
  1112. }
  1113. return fReturnVal;
  1114. }
  1115. STDMETHODIMP CCDData::LoadTitles(HWND hWnd)
  1116. {
  1117. HRESULT hr = E_FAIL;
  1118. Enter();
  1119. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1120. {
  1121. hr = S_OK;
  1122. if (m_pTitleList == NULL)
  1123. {
  1124. hr = ExtractTitles(&m_pTitleList, hWnd);
  1125. }
  1126. if (SUCCEEDED(hr))
  1127. {
  1128. m_dwLoadCnt++;
  1129. }
  1130. }
  1131. Leave();
  1132. return(hr);
  1133. }
  1134. STDMETHODIMP CCDData::PersistTitles()
  1135. {
  1136. Enter();
  1137. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1138. {
  1139. SaveTitles(&m_pTitleList);
  1140. }
  1141. Leave();
  1142. return S_OK;
  1143. }
  1144. STDMETHODIMP CCDData::UnloadTitles()
  1145. {
  1146. HRESULT hr = E_FAIL;
  1147. Enter();
  1148. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1149. {
  1150. if (m_pTitleList)
  1151. {
  1152. m_dwLoadCnt--;
  1153. if (m_dwLoadCnt == 0)
  1154. {
  1155. DestroyTitles(&m_pTitleList);
  1156. }
  1157. hr = S_OK;
  1158. }
  1159. }
  1160. Leave();
  1161. return(hr);
  1162. }
  1163. STDMETHODIMP CCDData::CreateTitle(LPCDTITLE *ppCDTitle, DWORD dwTitleID, DWORD dwNumTracks, DWORD dwNumMenus)
  1164. {
  1165. HRESULT hr = E_FAIL;
  1166. LPCDTITLE pCDTitle;
  1167. Enter();
  1168. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1169. {
  1170. hr = S_OK;
  1171. if (!QueryTitle(dwTitleID)) // Only create a blank if it's not already in database
  1172. {
  1173. RemoveFromBatch(dwTitleID);
  1174. hr = NewTitle(&pCDTitle, dwTitleID, dwNumTracks, dwNumMenus);
  1175. }
  1176. else
  1177. {
  1178. hr = LockTitle(&pCDTitle, dwTitleID); // Let's get return the one we got
  1179. if (SUCCEEDED(hr)) // but first, re-fit it according to params
  1180. {
  1181. if (pCDTitle->dwNumTracks != dwNumTracks)
  1182. {
  1183. if (pCDTitle->pTrackTable)
  1184. {
  1185. delete pCDTitle->pTrackTable;
  1186. }
  1187. pCDTitle->dwNumTracks = dwNumTracks;
  1188. pCDTitle->pTrackTable = new(CDTRACK[dwNumTracks]);
  1189. if (pCDTitle->pTrackTable == NULL)
  1190. {
  1191. hr = E_OUTOFMEMORY;
  1192. }
  1193. }
  1194. if (SUCCEEDED(hr) && pCDTitle->dwNumMenus != dwNumMenus)
  1195. {
  1196. if (pCDTitle->pMenuTable)
  1197. {
  1198. delete pCDTitle->pMenuTable;
  1199. }
  1200. pCDTitle->dwNumMenus = dwNumMenus;
  1201. pCDTitle->pMenuTable = new(CDMENU[dwNumMenus]);
  1202. ZeroMemory(pCDTitle->pMenuTable,sizeof(CDMENU)*dwNumMenus);
  1203. if (pCDTitle->pMenuTable == NULL)
  1204. {
  1205. hr = E_OUTOFMEMORY;
  1206. }
  1207. }
  1208. if (FAILED(hr))
  1209. {
  1210. DestroyTitle(pCDTitle);
  1211. }
  1212. }
  1213. }
  1214. if (SUCCEEDED(hr))
  1215. {
  1216. *ppCDTitle = pCDTitle;
  1217. }
  1218. }
  1219. Leave();
  1220. return(hr);
  1221. }
  1222. STDMETHODIMP CCDData::SetTitleQuery(LPCDTITLE pCDTitle, TCHAR *szTitleQuery)
  1223. {
  1224. HRESULT hr = E_FAIL;
  1225. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1226. {
  1227. if (pCDTitle && szTitleQuery && lstrlen(szTitleQuery) < INTERNET_MAX_PATH_LENGTH)
  1228. {
  1229. if (pCDTitle->szTitleQuery)
  1230. {
  1231. delete pCDTitle->szTitleQuery;
  1232. }
  1233. DWORD dwSize = lstrlen(szTitleQuery) + 1;
  1234. pCDTitle->szTitleQuery = new(TCHAR[dwSize]);
  1235. if (pCDTitle->szTitleQuery == NULL)
  1236. {
  1237. hr = E_OUTOFMEMORY;
  1238. }
  1239. else
  1240. {
  1241. lstrcpy(pCDTitle->szTitleQuery, szTitleQuery);
  1242. hr = S_OK;
  1243. }
  1244. }
  1245. }
  1246. return(hr);
  1247. }
  1248. STDMETHODIMP CCDData::SetMenuQuery(LPCDMENU pCDMenu, TCHAR *szMenuQuery)
  1249. {
  1250. HRESULT hr = E_FAIL;
  1251. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1252. {
  1253. if (pCDMenu && szMenuQuery && lstrlen(szMenuQuery) < INTERNET_MAX_PATH_LENGTH)
  1254. {
  1255. if (pCDMenu->szMenuQuery)
  1256. {
  1257. delete pCDMenu->szMenuQuery;
  1258. }
  1259. DWORD dwSize = lstrlen(szMenuQuery) + 1;
  1260. pCDMenu->szMenuQuery = new(TCHAR[dwSize]);
  1261. if (pCDMenu->szMenuQuery== NULL)
  1262. {
  1263. hr = E_OUTOFMEMORY;
  1264. }
  1265. else
  1266. {
  1267. lstrcpy(pCDMenu->szMenuQuery, szMenuQuery);
  1268. hr = S_OK;
  1269. }
  1270. }
  1271. }
  1272. return(hr);
  1273. }
  1274. STDMETHODIMP CCDData::NewTitle(LPCDTITLE *ppCDTitle, DWORD dwTitleID, DWORD dwNumTracks, DWORD dwNumMenus)
  1275. {
  1276. HRESULT hr = S_OK;
  1277. if (ppCDTitle == NULL || dwTitleID == CDTITLE_NODISC || dwNumTracks == 0)
  1278. {
  1279. hr = E_INVALIDARG;
  1280. }
  1281. else
  1282. {
  1283. LPCDTITLE pCDTitle = new(CDTITLE);
  1284. if (pCDTitle == NULL)
  1285. {
  1286. hr = E_OUTOFMEMORY;
  1287. }
  1288. else
  1289. {
  1290. memset(pCDTitle, 0, sizeof(CDTITLE));
  1291. pCDTitle->dwTitleID = dwTitleID;
  1292. pCDTitle->dwNumTracks = dwNumTracks;
  1293. pCDTitle->dwNumMenus = dwNumMenus;
  1294. pCDTitle->fLoaded = TRUE;
  1295. pCDTitle->dwLockCnt = 1;
  1296. pCDTitle->pTrackTable = new(CDTRACK[dwNumTracks]);
  1297. if (pCDTitle->pTrackTable == NULL)
  1298. {
  1299. hr = E_OUTOFMEMORY;
  1300. }
  1301. else
  1302. {
  1303. memset(pCDTitle->pTrackTable, 0, sizeof(CDTRACK) * dwNumTracks);
  1304. if (dwNumMenus)
  1305. {
  1306. pCDTitle->pMenuTable = new(CDMENU[dwNumMenus]);
  1307. if (pCDTitle->pMenuTable == NULL)
  1308. {
  1309. hr = E_OUTOFMEMORY;
  1310. }
  1311. else
  1312. {
  1313. memset(pCDTitle->pMenuTable, 0, sizeof(CDMENU) * dwNumMenus);
  1314. }
  1315. }
  1316. }
  1317. if (FAILED(hr))
  1318. {
  1319. if (pCDTitle->pMenuTable)
  1320. {
  1321. delete pCDTitle->pMenuTable;
  1322. }
  1323. if (pCDTitle->pTrackTable)
  1324. {
  1325. delete pCDTitle->pTrackTable;
  1326. }
  1327. delete(pCDTitle);
  1328. }
  1329. else
  1330. {
  1331. *ppCDTitle = pCDTitle;
  1332. }
  1333. }
  1334. }
  1335. return(hr);
  1336. }
  1337. STDMETHODIMP_(void) CCDData::DestroyTitle(LPCDTITLE pCDTitle)
  1338. {
  1339. if (pCDTitle)
  1340. {
  1341. if (pCDTitle->szTitleQuery)
  1342. {
  1343. delete pCDTitle->szTitleQuery;
  1344. }
  1345. if (pCDTitle->pTrackTable)
  1346. {
  1347. delete pCDTitle->pTrackTable;
  1348. }
  1349. if (pCDTitle->pPlayList)
  1350. {
  1351. delete pCDTitle->pPlayList;
  1352. }
  1353. if (pCDTitle->pMenuTable)
  1354. {
  1355. for (DWORD dwMenu = 0; dwMenu < pCDTitle->dwNumMenus; dwMenu++)
  1356. {
  1357. TCHAR *szMenuQuery = pCDTitle->pMenuTable[dwMenu].szMenuQuery;
  1358. if (szMenuQuery)
  1359. {
  1360. delete szMenuQuery;
  1361. }
  1362. }
  1363. delete pCDTitle->pMenuTable;
  1364. }
  1365. }
  1366. delete pCDTitle;
  1367. }
  1368. STDMETHODIMP_(void) CCDData::SaveTitle(LPCDTITLE pCDTitle, BOOL fExist)
  1369. {
  1370. UCHAR szQuery[MAX_PATH];
  1371. UDWORD row[NUMTABLES];
  1372. UWORD rgfRowStat[NUMTABLES][ROWSET];
  1373. RETCODE rc;
  1374. if (fExist)
  1375. {
  1376. wsprintf((TCHAR *) szQuery, TEXT("select * from Titles where TitleID = %d"), pCDTitle->dwTitleID);
  1377. rc = m_pSQL->ExecDirect(m_hstmt[0], szQuery, SQL_NTS);
  1378. ReportError(&m_bd, m_hstmt[0]);
  1379. }
  1380. else
  1381. {
  1382. rc = m_pSQL->ExecDirect(m_hstmt[0], (UCHAR *) TEXT("select * from Titles"), SQL_NTS);
  1383. ReportError(&m_bd, m_hstmt[0]);
  1384. }
  1385. rc = m_pSQL->ExtendedFetch(m_hstmt[0], SQL_FETCH_LAST, 1, &row[0], rgfRowStat[0]);
  1386. ReportError(&m_bd, m_hstmt[0]);
  1387. InitCBTable(&m_bd);
  1388. memcpy(&m_bd.CDTitle, pCDTitle, sizeof(CDTITLE));
  1389. if (pCDTitle->szTitleQuery)
  1390. {
  1391. lstrcpy(m_bd.szQuery, pCDTitle->szTitleQuery);
  1392. }
  1393. else
  1394. {
  1395. m_bd.szQuery[0] = TEXT('\0');
  1396. }
  1397. pCDTitle->dwNumPlay = min(pCDTitle->dwNumPlay, MAXNUMPLAY);
  1398. m_bd.szPlayList[0] = TEXT('\0');
  1399. if (pCDTitle->dwNumPlay && pCDTitle->pPlayList)
  1400. {
  1401. DWORD dwIndex;
  1402. TCHAR *pDst = m_bd.szPlayList;
  1403. LPWORD pNum = pCDTitle->pPlayList;
  1404. for (dwIndex = 0; dwIndex < pCDTitle->dwNumPlay; dwIndex++, pNum++)
  1405. {
  1406. wsprintf(pDst, TEXT("%02x"), *pNum);
  1407. while(*pDst != TEXT('\0'))
  1408. {
  1409. pDst++;
  1410. }
  1411. }
  1412. }
  1413. if (fExist)
  1414. {
  1415. rc = m_pSQL->SetPos(m_hstmt[0], 0, SQL_UPDATE, SQL_LOCK_NO_CHANGE);
  1416. // ReportError(&m_bd, m_hstmt[0]);
  1417. }
  1418. else
  1419. {
  1420. rc = m_pSQL->SetPos(m_hstmt[0], 0, SQL_ADD, SQL_LOCK_NO_CHANGE);
  1421. // ReportError(&m_bd, m_hstmt[0]);
  1422. }
  1423. }
  1424. STDMETHODIMP_(void) CCDData::SaveTracks(LPCDTITLE pCDTitle, BOOL fExist)
  1425. {
  1426. UCHAR szQuery[MAX_PATH];
  1427. UDWORD row[NUMTABLES];
  1428. UWORD rgfRowStat[NUMTABLES][ROWSET];
  1429. RETCODE rc;
  1430. DWORD dwTrack;
  1431. DWORD dwTitleID = pCDTitle->dwTitleID;
  1432. if (fExist)
  1433. {
  1434. wsprintf((TCHAR *) szQuery, TEXT("select * from Tracks where TitleID = %d"), pCDTitle->dwTitleID);
  1435. rc = m_pSQL->ExecDirect(m_hstmt[1], szQuery, SQL_NTS);
  1436. ReportError(&m_bd, m_hstmt[1]);
  1437. }
  1438. else
  1439. {
  1440. rc = m_pSQL->ExecDirect(m_hstmt[1], (UCHAR *) TEXT("select * from Tracks"), SQL_NTS);
  1441. ReportError(&m_bd, m_hstmt[1]);
  1442. }
  1443. if (fExist)
  1444. {
  1445. rc = m_pSQL->ExtendedFetch(m_hstmt[1], SQL_FETCH_FIRST, 1, &row[0], rgfRowStat[0]);
  1446. ReportError(&m_bd, m_hstmt[1]);
  1447. for (dwTrack = 0; dwTrack < pCDTitle->dwNumTracks; dwTrack++)
  1448. {
  1449. InitCBTable(&m_bd);
  1450. m_bd.CDTitle.dwTitleID = dwTitleID;
  1451. if (m_bd.dwTrackID < pCDTitle->dwNumTracks)
  1452. {
  1453. memcpy(&m_bd.CDTrack, &(pCDTitle->pTrackTable[m_bd.dwTrackID]), sizeof(CDTRACK));
  1454. rc = m_pSQL->SetPos(m_hstmt[1], 0, SQL_UPDATE, SQL_LOCK_NO_CHANGE);
  1455. ReportError(&m_bd, m_hstmt[1]);
  1456. }
  1457. rc = m_pSQL->ExtendedFetch(m_hstmt[1], SQL_FETCH_NEXT, 1, &row[0], rgfRowStat[0]);
  1458. ReportError(&m_bd, m_hstmt[1]);
  1459. }
  1460. }
  1461. else
  1462. {
  1463. rc = m_pSQL->ExtendedFetch(m_hstmt[1], SQL_FETCH_LAST, 1, &row[0], rgfRowStat[0]);
  1464. ReportError(&m_bd, m_hstmt[1]);
  1465. InitCBTable(&m_bd);
  1466. m_bd.CDTitle.dwTitleID = dwTitleID;
  1467. for (dwTrack = 0; dwTrack < pCDTitle->dwNumTracks; dwTrack++)
  1468. {
  1469. m_bd.dwTrackID = dwTrack;
  1470. memcpy(&m_bd.CDTrack, &(pCDTitle->pTrackTable[dwTrack]), sizeof(CDTRACK));
  1471. rc = m_pSQL->SetPos(m_hstmt[1], 0, SQL_ADD, SQL_LOCK_NO_CHANGE);
  1472. ReportError(&m_bd, m_hstmt[1]);
  1473. }
  1474. }
  1475. }
  1476. STDMETHODIMP_(void) CCDData::SaveMenus(LPCDTITLE pCDTitle)
  1477. {
  1478. UCHAR szQuery[MAX_PATH];
  1479. UDWORD row[NUMTABLES];
  1480. UWORD rgfRowStat[NUMTABLES][ROWSET];
  1481. RETCODE rc;
  1482. DWORD dwMenu;
  1483. DWORD dwTitleID = pCDTitle->dwTitleID;
  1484. wsprintf((TCHAR *) szQuery, TEXT("delete from Menus where TitleID = %d"), pCDTitle->dwTitleID);
  1485. rc = m_pSQL->ExecDirect(m_hstmt[2], szQuery, SQL_NTS);
  1486. if (pCDTitle->dwNumMenus)
  1487. {
  1488. rc = m_pSQL->ExecDirect(m_hstmt[2], (UCHAR *) TEXT("select * from Menus"), SQL_NTS);
  1489. ReportError(&m_bd, m_hstmt[2]);
  1490. rc = m_pSQL->ExtendedFetch(m_hstmt[2], SQL_FETCH_LAST, 1, &row[0], rgfRowStat[0]);
  1491. ReportError(&m_bd, m_hstmt[2]);
  1492. InitCBTable(&m_bd);
  1493. m_bd.CDTitle.dwTitleID = dwTitleID;
  1494. for (dwMenu = 0; dwMenu < pCDTitle->dwNumMenus; dwMenu++)
  1495. {
  1496. LPCDMENU pCDMenu = &(pCDTitle->pMenuTable[dwMenu]);
  1497. m_bd.dwMenuID = dwMenu;
  1498. memcpy(&m_bd.CDMenu, pCDMenu, sizeof(CDMENU));
  1499. m_bd.szQuery[0] = TEXT('\0');
  1500. if (pCDMenu->szMenuQuery)
  1501. {
  1502. lstrcpy(m_bd.szQuery, pCDMenu->szMenuQuery);
  1503. }
  1504. rc = m_pSQL->SetPos(m_hstmt[2], 0, SQL_ADD, SQL_LOCK_NO_CHANGE);
  1505. //ReportError(&m_bd, m_hstmt[2]);
  1506. }
  1507. }
  1508. }
  1509. STDMETHODIMP_(void) CCDData::DBSaveTitle(LPCDTITLE pCDTitle)
  1510. {
  1511. if (pCDTitle)
  1512. {
  1513. RETCODE rc;
  1514. DWORD dwIndex;
  1515. BOOL fExist = QueryDatabase(pCDTitle->dwTitleID, gszTitleTable);
  1516. InitCBTable(&m_bd);
  1517. SetCursors( m_hstmt );
  1518. SetBindings( m_hstmt, &m_bd);
  1519. rc = m_pSQL->SetConnectOption(m_hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
  1520. ReportError(&m_bd, m_hstmt[0]);
  1521. SaveTitle(pCDTitle, fExist);
  1522. SaveTracks(pCDTitle, fExist);
  1523. SaveMenus(pCDTitle);
  1524. rc = m_pSQL->Transact(SQL_NULL_HENV, m_hdbc, SQL_COMMIT);
  1525. // ReportError(&m_bd, m_hstmt[0]);
  1526. rc = m_pSQL->SetConnectOption(m_hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
  1527. // ReportError(&m_bd, m_hstmt[0]);
  1528. for (dwIndex = 0; dwIndex < NUMTABLES; dwIndex++)
  1529. {
  1530. m_pSQL->FreeStmt(m_hstmt[dwIndex], SQL_CLOSE);
  1531. }
  1532. }
  1533. }
  1534. STDMETHODIMP_(void) CCDData::DBRemoveTitle(LPCDTITLE pCDTitle)
  1535. {
  1536. if (pCDTitle && pCDTitle->dwTitleID != CDTITLE_NODISC)
  1537. {
  1538. RETCODE rc;
  1539. UCHAR szQuery[MAX_PATH];
  1540. HSTMT hstmt;
  1541. if (m_pSQL->AllocStmt(m_hdbc, &hstmt) == SQL_SUCCESS)
  1542. {
  1543. wsprintf((TCHAR *) szQuery, TEXT("delete from Titles where TitleID = %d"), pCDTitle->dwTitleID);
  1544. rc = m_pSQL->ExecDirect(hstmt, szQuery, SQL_NTS);
  1545. wsprintf((TCHAR *) szQuery, TEXT("delete from Tracks where TitleID = %d"), pCDTitle->dwTitleID);
  1546. rc = m_pSQL->ExecDirect(hstmt, szQuery, SQL_NTS);
  1547. wsprintf((TCHAR *) szQuery, TEXT("delete from Menus where TitleID = %d"), pCDTitle->dwTitleID);
  1548. rc = m_pSQL->ExecDirect(hstmt, szQuery, SQL_NTS);
  1549. m_pSQL->FreeStmt(hstmt, SQL_DROP);
  1550. }
  1551. }
  1552. }
  1553. STDMETHODIMP_(void) CCDData::DestroyTitles(LPCDTITLE *ppCDTitles)
  1554. {
  1555. if (ppCDTitles && *ppCDTitles)
  1556. {
  1557. LPCDTITLE pNext;
  1558. LPCDTITLE pCDTitle = *ppCDTitles;
  1559. *ppCDTitles = NULL;
  1560. pNext = pCDTitle;
  1561. while (pCDTitle)
  1562. {
  1563. pNext = pCDTitle->pNext;
  1564. if (pCDTitle->dwLockCnt) // Someone locked a node that was in memory and have unloaded before unlocking
  1565. { // We will abandon the node, it will be destroyed when they unlock it.
  1566. pCDTitle->fLoaded = TRUE;
  1567. pCDTitle->pNext = NULL;
  1568. }
  1569. else
  1570. {
  1571. DestroyTitle(pCDTitle);
  1572. }
  1573. pCDTitle = pNext;
  1574. }
  1575. }
  1576. }
  1577. STDMETHODIMP_(void) CCDData::SaveTitles(LPCDTITLE *ppCDTitles)
  1578. {
  1579. if (ppCDTitles && *ppCDTitles)
  1580. {
  1581. LPCDTITLE pLast = NULL;
  1582. LPCDTITLE pNext;
  1583. LPCDTITLE pCDTitle = *ppCDTitles;
  1584. pNext = pCDTitle;
  1585. while (pCDTitle)
  1586. {
  1587. pNext = pCDTitle->pNext;
  1588. if (pCDTitle->fRemove)
  1589. {
  1590. if (pCDTitle->dwTitleID != DWORD(-1))
  1591. {
  1592. DBRemoveTitle(pCDTitle);
  1593. }
  1594. if (pLast == NULL)
  1595. {
  1596. *ppCDTitles = pNext;
  1597. }
  1598. else
  1599. {
  1600. pLast->pNext = pNext;
  1601. }
  1602. DestroyTitle(pCDTitle);
  1603. }
  1604. else
  1605. {
  1606. if (pCDTitle->fChanged)
  1607. {
  1608. DBSaveTitle(pCDTitle);
  1609. pCDTitle->fChanged = FALSE;
  1610. }
  1611. pLast = pCDTitle;
  1612. }
  1613. pCDTitle = pNext;
  1614. }
  1615. }
  1616. }
  1617. STDMETHODIMP_(void) CCDData::AddTitle(LPCDTITLE *ppCDTitles, LPCDTITLE pCDNewTitle)
  1618. {
  1619. if (ppCDTitles && pCDNewTitle)
  1620. {
  1621. if (*ppCDTitles == NULL) // Inserting into empty list
  1622. {
  1623. *ppCDTitles = pCDNewTitle;
  1624. pCDNewTitle->pNext = NULL;
  1625. }
  1626. else // Insertion sort based on artist name (for view by artist feature)
  1627. {
  1628. LPCDTITLE pCDTitle = *ppCDTitles;
  1629. LPCDTITLE pLast = NULL;
  1630. TCHAR *szArtist = pCDNewTitle->szArtist;
  1631. while (pCDTitle)
  1632. {
  1633. if (lstrcmp(pCDTitle->szArtist, szArtist) >= 0) // we'll only sort by artist, the tree control will sort titles for us
  1634. {
  1635. if (pLast == NULL) // insert at head of list
  1636. {
  1637. pCDNewTitle->pNext = *ppCDTitles;
  1638. *ppCDTitles = pCDNewTitle;
  1639. }
  1640. else
  1641. {
  1642. pCDNewTitle->pNext = pCDTitle;
  1643. pLast->pNext = pCDNewTitle;
  1644. }
  1645. break;
  1646. }
  1647. if (pCDTitle->pNext == NULL) // Insert on end of list
  1648. {
  1649. pCDTitle->pNext = pCDNewTitle;
  1650. pCDNewTitle->pNext = NULL;
  1651. break;
  1652. }
  1653. pLast = pCDTitle;
  1654. pCDTitle = pCDTitle->pNext;
  1655. }
  1656. }
  1657. }
  1658. }
  1659. STDMETHODIMP_(LPCDTITLE) CCDData::GetTitleList(void)
  1660. {
  1661. LPCDTITLE pCDTitle;
  1662. Enter();
  1663. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1664. {
  1665. pCDTitle = m_pTitleList;
  1666. }
  1667. Leave();
  1668. return(pCDTitle);
  1669. }
  1670. STDMETHODIMP_(DWORD) CCDData::GetNumBatched(void)
  1671. {
  1672. DWORD dwCount = 0;
  1673. Enter();
  1674. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1675. {
  1676. if (m_pBatchList == NULL) // Batch Not in memory, just query Batch database directly
  1677. {
  1678. dwCount = GetNumRows((UCHAR *) gszBatchTable);
  1679. }
  1680. else
  1681. {
  1682. LPCDBATCH pCDBatch = m_pBatchList;
  1683. while (pCDBatch)
  1684. {
  1685. if (!pCDBatch->fRemove)
  1686. {
  1687. dwCount++;
  1688. }
  1689. pCDBatch = pCDBatch->pNext;
  1690. }
  1691. }
  1692. }
  1693. Leave();
  1694. return(dwCount);
  1695. }
  1696. STDMETHODIMP_(BOOL) CCDData::FindBatchTitle(LPCDBATCH pCDBatchList, DWORD dwTitleID)
  1697. {
  1698. BOOL fFound = FALSE;
  1699. LPCDBATCH pCDBatch = pCDBatchList;
  1700. while (pCDBatch)
  1701. {
  1702. if (pCDBatch->dwTitleID == dwTitleID)
  1703. {
  1704. if (!pCDBatch->fRemove)
  1705. {
  1706. fFound = TRUE;
  1707. }
  1708. break;
  1709. }
  1710. pCDBatch = pCDBatch->pNext;
  1711. }
  1712. return(fFound);
  1713. }
  1714. STDMETHODIMP_(BOOL) CCDData::QueryBatch(DWORD dwTitleID)
  1715. {
  1716. BOOL fFound = FALSE;
  1717. Enter();
  1718. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1719. {
  1720. if (m_pBatchList == NULL) // Batch Not in memory, just query Batch database directly
  1721. {
  1722. fFound = QueryDatabase(dwTitleID, gszBatchTable);
  1723. }
  1724. else // Batch is in memory, just look here.
  1725. {
  1726. fFound = FindBatchTitle(m_pBatchList, dwTitleID);
  1727. }
  1728. }
  1729. Leave();
  1730. return(fFound);
  1731. }
  1732. STDMETHODIMP CCDData::ExtractBatch(LPCDBATCH *ppCDBatchList, HWND hWnd)
  1733. {
  1734. HRESULT hr = E_FAIL;
  1735. LPCDBATCH pCDBatch= NULL;
  1736. TIMEDMETER tm;
  1737. InitCBTable(&m_bd);
  1738. SetCursors(m_hstmt);
  1739. SetBindings(m_hstmt, &m_bd);
  1740. if (ppCDBatchList == NULL || m_henv == NULL)
  1741. {
  1742. hr = E_INVALIDARG;
  1743. }
  1744. else
  1745. {
  1746. RETCODE rc;
  1747. DWORD dwCount = GetNumRows((UCHAR *) gszBatchTable);
  1748. CreateMeter(&tm, hWnd, dwCount, 100, 0);
  1749. dwCount = 0;
  1750. rc = m_pSQL->ExecDirect(m_hstmt[3], (UCHAR *) TEXT("select * from Batch"), SQL_NTS);
  1751. if (rc == SQL_SUCCESS)
  1752. {
  1753. m_bd.szQuery[0] = TEXT('\0');
  1754. while (m_pSQL->Fetch(m_hstmt[3]) == SQL_SUCCESS)
  1755. {
  1756. pCDBatch = new CDBATCH;
  1757. if (pCDBatch == NULL)
  1758. {
  1759. hr = E_OUTOFMEMORY;
  1760. break;
  1761. }
  1762. else
  1763. {
  1764. DWORD dwSize = lstrlen(m_bd.szQuery) + 1;
  1765. pCDBatch->szTitleQuery = new(TCHAR[dwSize]);
  1766. if (pCDBatch->szTitleQuery == NULL)
  1767. {
  1768. delete pCDBatch;
  1769. hr = E_OUTOFMEMORY;
  1770. break;
  1771. }
  1772. else
  1773. {
  1774. lstrcpy(pCDBatch->szTitleQuery, m_bd.szQuery);
  1775. pCDBatch->dwTitleID = m_bd.CDTitle.dwTitleID;
  1776. pCDBatch->dwNumTracks = m_bd.CDTitle.dwNumTracks;
  1777. pCDBatch->fRemove = FALSE;
  1778. pCDBatch->fFresh = TRUE;
  1779. pCDBatch->pNext = *ppCDBatchList;
  1780. *ppCDBatchList = pCDBatch;
  1781. m_bd.szQuery[0] = TEXT('\0');
  1782. UpdateMeter(&tm);
  1783. hr = S_OK;
  1784. }
  1785. }
  1786. }
  1787. m_pSQL->FreeStmt(m_hstmt[3], SQL_CLOSE);
  1788. }
  1789. DestroyMeter(&tm);
  1790. }
  1791. return(hr);
  1792. }
  1793. STDMETHODIMP CCDData::LoadBatch(HWND hWnd, LPCDBATCH *ppCDBatchList)
  1794. {
  1795. HRESULT hr = E_FAIL;
  1796. Enter();
  1797. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1798. {
  1799. if (ppCDBatchList)
  1800. {
  1801. if (m_pBatchList == NULL)
  1802. {
  1803. hr = ExtractBatch(&m_pBatchList, hWnd);
  1804. if (SUCCEEDED(hr))
  1805. {
  1806. m_dwBatchCnt++;
  1807. *ppCDBatchList = m_pBatchList;
  1808. }
  1809. }
  1810. }
  1811. }
  1812. Leave();
  1813. return(hr);
  1814. }
  1815. STDMETHODIMP_(void) CCDData::DeleteBatch(LPCDBATCH pCDBatch)
  1816. {
  1817. RETCODE rc;
  1818. UCHAR szQuery[MAX_PATH];
  1819. HSTMT hstmt;
  1820. if (pCDBatch->fRemove)
  1821. {
  1822. if (m_pSQL->AllocStmt(m_hdbc, &hstmt) == SQL_SUCCESS)
  1823. {
  1824. wsprintf((TCHAR *) szQuery, TEXT("delete from Batch where TitleID = %d"), pCDBatch->dwTitleID);
  1825. rc = m_pSQL->ExecDirect(hstmt, szQuery, SQL_NTS);
  1826. m_pSQL->FreeStmt(hstmt, SQL_DROP);
  1827. }
  1828. }
  1829. if (pCDBatch->szTitleQuery)
  1830. {
  1831. delete pCDBatch->szTitleQuery;
  1832. }
  1833. delete pCDBatch;
  1834. }
  1835. STDMETHODIMP_(void) CCDData::DestroyBatch(LPCDBATCH *ppCDBatchList)
  1836. {
  1837. if (ppCDBatchList && *ppCDBatchList)
  1838. {
  1839. LPCDBATCH pNext;
  1840. LPCDBATCH pCDBatch = *ppCDBatchList;
  1841. *ppCDBatchList = NULL;
  1842. while (pCDBatch)
  1843. {
  1844. pNext = pCDBatch->pNext;
  1845. DeleteBatch(pCDBatch);
  1846. pCDBatch = pNext;
  1847. }
  1848. }
  1849. }
  1850. STDMETHODIMP CCDData::UnloadBatch(LPCDBATCH pCDBatchList)
  1851. {
  1852. HRESULT hr = E_FAIL;
  1853. Enter();
  1854. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1855. {
  1856. if (pCDBatchList == m_pBatchList && m_dwBatchCnt)
  1857. {
  1858. m_dwBatchCnt--;
  1859. if (m_dwBatchCnt == 0)
  1860. {
  1861. DestroyBatch(&m_pBatchList);
  1862. }
  1863. hr = S_OK;
  1864. }
  1865. }
  1866. Leave();
  1867. return(hr);
  1868. }
  1869. STDMETHODIMP CCDData::DumpBatch(void)
  1870. {
  1871. HRESULT hr = E_FAIL;
  1872. Enter();
  1873. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1874. {
  1875. if (m_dwBatchCnt == 0)
  1876. {
  1877. HSTMT hstmt;
  1878. if (m_pSQL->AllocStmt(m_hdbc, &hstmt) == SQL_SUCCESS)
  1879. {
  1880. m_pSQL->ExecDirect(hstmt, (UCHAR *) TEXT("drop table Batch"), SQL_NTS);
  1881. m_pSQL->ExecDirect(hstmt, (UCHAR *) gszBatchCreate, SQL_NTS);
  1882. m_pSQL->FreeStmt(hstmt, SQL_CLOSE);
  1883. m_pSQL->FreeStmt(hstmt, SQL_DROP);
  1884. hr = S_OK;
  1885. }
  1886. }
  1887. }
  1888. Leave();
  1889. return (hr);
  1890. }
  1891. STDMETHODIMP_(void) CCDData::RemoveFromBatch(DWORD dwTitleID)
  1892. {
  1893. if (QueryBatch(dwTitleID))
  1894. {
  1895. if (m_pBatchList)
  1896. {
  1897. LPCDBATCH pBatch = m_pBatchList;
  1898. while(pBatch)
  1899. {
  1900. if (pBatch->dwTitleID == dwTitleID)
  1901. {
  1902. pBatch->fRemove = TRUE;
  1903. break;
  1904. }
  1905. pBatch = pBatch->pNext;
  1906. }
  1907. }
  1908. else
  1909. {
  1910. RETCODE rc;
  1911. UCHAR szQuery[MAX_PATH];
  1912. HSTMT hstmt;
  1913. if (m_pSQL->AllocStmt(m_hdbc, &hstmt) == SQL_SUCCESS)
  1914. {
  1915. wsprintf((TCHAR *) szQuery, TEXT("delete from Batch where TitleID = %d"), dwTitleID);
  1916. rc = m_pSQL->ExecDirect(hstmt, szQuery, SQL_NTS);
  1917. m_pSQL->FreeStmt(hstmt, SQL_DROP);
  1918. }
  1919. }
  1920. }
  1921. }
  1922. STDMETHODIMP CCDData::AddToBatch(DWORD dwTitleID, TCHAR *szTitleQuery, DWORD dwNumTracks)
  1923. {
  1924. HRESULT hr = E_FAIL;
  1925. Enter();
  1926. if (SUCCEEDED(GetSQLPtr(FALSE)))
  1927. {
  1928. if (!QueryBatch(dwTitleID) && szTitleQuery && (UINT)lstrlen(szTitleQuery) < (sizeof(m_bd.szQuery)/sizeof(TCHAR)))
  1929. {
  1930. RETCODE rc;
  1931. DWORD dwIndex;
  1932. UDWORD row;
  1933. UWORD rgfRowStat[ROWSET];
  1934. InitCBTable(&m_bd);
  1935. SetCursors( m_hstmt );
  1936. SetBindings( m_hstmt, &m_bd);
  1937. m_pSQL->SetConnectOption(m_hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
  1938. rc = m_pSQL->ExecDirect(m_hstmt[3], (UCHAR *) TEXT("select * from Batch"), SQL_NTS);
  1939. ReportError(&m_bd, m_hstmt[3]);
  1940. rc = m_pSQL->ExtendedFetch(m_hstmt[3], SQL_FETCH_LAST, 1, &row, rgfRowStat);
  1941. ReportError(&m_bd, m_hstmt[3]);
  1942. InitCBTable(&m_bd);
  1943. m_bd.CDTitle.dwTitleID = dwTitleID;
  1944. m_bd.CDTitle.dwNumTracks = dwNumTracks;
  1945. lstrcpy(m_bd.szQuery, szTitleQuery);
  1946. rc = m_pSQL->SetPos(m_hstmt[3], 0, SQL_ADD, SQL_LOCK_NO_CHANGE);
  1947. // ReportError(&m_bd, m_hstmt[3]);
  1948. rc = m_pSQL->Transact(SQL_NULL_HENV, m_hdbc, SQL_COMMIT);
  1949. // ReportError(&m_bd, m_hstmt[3]);
  1950. m_pSQL->SetConnectOption(m_hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
  1951. for (dwIndex = 0; dwIndex < NUMTABLES; dwIndex++)
  1952. {
  1953. m_pSQL->FreeStmt(m_hstmt[dwIndex], SQL_CLOSE);
  1954. }
  1955. hr = S_OK;
  1956. }
  1957. }
  1958. Leave();
  1959. return(hr);
  1960. }
  1961. STDMETHODIMP_(BOOL) CCDData::IsOldFormat()
  1962. {
  1963. BOOL fResult = FALSE;
  1964. TCHAR szName[MAX_PATH];
  1965. SQLSMALLINT nName;
  1966. SQLSMALLINT sqlType;
  1967. SQLUINTEGER dwColDef;
  1968. SQLSMALLINT ibScale;
  1969. SQLSMALLINT fNullable;
  1970. RETCODE rc = SQL_SUCCESS;
  1971. rc = m_pSQL->ExecDirect(m_hstmt[0], (UCHAR *) TEXT("select * from Titles"), SQL_NTS);
  1972. if (SQL_SUCCEEDED(rc))
  1973. {
  1974. //check "artist" and "titlequery" columns to find out if this is an old-format db.
  1975. //if either is the old type, then this is an old-format db
  1976. rc = m_pSQL->DescribeCol(m_hstmt[0], 2, (UCHAR*)(&szName), sizeof(szName), &nName, &sqlType, &dwColDef, &ibScale, &fNullable);
  1977. if (SQL_SUCCEEDED(rc))
  1978. {
  1979. if (sqlType != SQL_LONGCHAR_FIELD)
  1980. {
  1981. fResult = TRUE;
  1982. }
  1983. }
  1984. rc = m_pSQL->DescribeCol(m_hstmt[0], 10, (UCHAR*)(&szName), sizeof(szName), &nName, &sqlType, &dwColDef, &ibScale, &fNullable);
  1985. if (SQL_SUCCEEDED(rc))
  1986. {
  1987. if (sqlType == SQL_C_BINARY)
  1988. {
  1989. fResult = TRUE;
  1990. }
  1991. }
  1992. }
  1993. m_pSQL->FreeStmt(m_hstmt[0],SQL_CLOSE);
  1994. return (fResult);
  1995. }
  1996. STDMETHODIMP CCDData::UpgradeDatabase(HWND hWnd)
  1997. {
  1998. HRESULT hr = S_OK;
  1999. HSTMT hstmt = NULL;
  2000. TIMEDMETER tm;
  2001. DWORD dwCount = GetNumRows((UCHAR *) gszTitleTable)
  2002. + GetNumRows((UCHAR *) gszBatchTable);
  2003. //steps:
  2004. //1. Read values from old version of database
  2005. //2. Delete the original database
  2006. //3. Create new database with correct data types
  2007. //4. Put data into new database
  2008. //5. Clean up
  2009. //Step 1: Read values from old version of database
  2010. LPCDBATCH pBatchList = NULL;
  2011. LoadTitles(hWnd); //(also gets tracks and menus)
  2012. LoadBatch(hWnd,&pBatchList);
  2013. //Step 2: Delete the original database
  2014. CloseDatabase();
  2015. TCHAR szFileName[MAX_PATH];
  2016. GetWindowsDirectory(szFileName,sizeof(szFileName)/sizeof(TCHAR));
  2017. _tcscat(szFileName,TEXT("\\DeluxeCD.MDB"));
  2018. DeleteFile(szFileName);
  2019. //Step 3: Create new database with correct data types
  2020. CreateDatabase();
  2021. ConnectToDatabase(ODBC_CONFIG_DSN);
  2022. //Step 4: Put data into new database
  2023. CreateMeter(&tm, hWnd, dwCount, 5, IDS_IMPORTING);
  2024. //put all the titles into the new db
  2025. LPCDTITLE pCDTitle = m_pTitleList;
  2026. while (pCDTitle)
  2027. {
  2028. DBSaveTitle(pCDTitle);
  2029. UpdateMeter(&tm);
  2030. pCDTitle = pCDTitle->pNext;
  2031. }
  2032. //put all the batches into the new db
  2033. LPCDBATCH pBatch = pBatchList;
  2034. while (pBatch)
  2035. {
  2036. AddToBatch(pBatch->dwTitleID,pBatch->szTitleQuery,pBatch->dwNumTracks);
  2037. pBatch->fRemove = FALSE;
  2038. UpdateMeter(&tm);
  2039. pBatch = pBatch->pNext;
  2040. }
  2041. //Step 5: Clean up
  2042. UnloadBatch(pBatchList);
  2043. DestroyMeter(&tm);
  2044. return (hr);
  2045. }