ExtendedFileInfo.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241
  1. #define SKIP_OVER
  2. #include "main.h"
  3. #include "api__in_cdda.h"
  4. #include "CDPlay.h"
  5. #include "DAEPlay.h"
  6. #include "MCIPlay.h"
  7. #include "WindacPlay.h"
  8. #include "cddb.h"
  9. #include "../nu/AutoWide.h"
  10. #include "../nu/AutoChar.h"
  11. #include "../nde/ndestring.h"
  12. #include "../nu/ListView.h"
  13. #ifndef IGNORE_API_GRACENOTE
  14. #include "../primo/obj_primo.h"
  15. #endif
  16. #include "../Winamp/wa_ipc.h"
  17. #include <api/service/waservicefactory.h>
  18. #include <shlwapi.h>
  19. #include <atlbase.h>
  20. #include <strsafe.h>
  21. #if 0
  22. BOOL CALLBACK ripConfigProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  23. #endif
  24. static int cachedev_used;
  25. static MCIDEVICEID cachedev;
  26. static wchar_t last_fn[8];
  27. extern "C" __declspec(dllexport) int winampGetExtendedFileInfoW(const wchar_t *fn, const char *data, wchar_t *dest, int destlen)
  28. {
  29. s_last_error = NULL;
  30. if (!_stricmp(data, "type"))
  31. {
  32. lstrcpynW(dest, L"0", destlen); //audio
  33. return 1;
  34. }
  35. else if (!_stricmp(data, "family"))
  36. {
  37. LPCWSTR e, p(NULL);
  38. DWORD lcid;
  39. e = PathFindExtensionW(fn);
  40. if (L'.' != *e) return 0;
  41. e++;
  42. lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
  43. if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, e, -1, L"CDA", -1)) p = WASABI_API_LNGSTRINGW(IDS_FAMILY_STRING);
  44. if (p && S_OK == StringCchCopyW(dest, destlen, p)) return 1;
  45. return 0;
  46. }
  47. else if (!_stricmp(data, "ext_cdda"))
  48. {
  49. lstrcpynW(dest, L"1", destlen); //audio
  50. return 1;
  51. }
  52. // TODO determine if we even keep any of this...
  53. /*
  54. else if (!_stricmp(data, "cdda_config_text"))
  55. {
  56. WASABI_API_LNGSTRINGW_BUF(IDS_RIPPING,dest,destlen);
  57. return 1;
  58. }
  59. else if (!_strnicmp(data, "cdda_cf_", 8))
  60. {
  61. HWND parent = (HWND)atoi(data + 8);
  62. dest[0] = 0;
  63. if (parent && IsWindow(parent))
  64. {
  65. parent = WASABI_API_CREATEDIALOGW(IDD_PREFS_CDRIP, parent, ripConfigProc);
  66. _itow((int)parent, dest, 10);
  67. }
  68. return 1;
  69. }
  70. */
  71. if (!lstrcmpiW(PathFindExtensionW(fn), L".cda") && !_wcsnicmp(fn + 1, L":\\track", 7)) // stupid hack, converts x:\\trackXX.cda to cda://x,XX
  72. {
  73. static wchar_t fakebuf[128];
  74. StringCchPrintf(fakebuf, 128, L"cda://%c,%d", fn[0], _wtoi(PathFindFileNameW(fn) + 5));
  75. fn = fakebuf;
  76. }
  77. if (!_wcsnicmp(fn, L"cda://", 6)) // determine length of cd track via MCI
  78. {
  79. int track = lstrlenW(fn) > 8 ? _wtoi(fn + 8) : 0;
  80. int device = fn[6];
  81. if (device >= 'a' && device <= 'z') device += 'A' -'a';
  82. MCIDEVICEID dev2 = 0;
  83. if (cachedev_used) dev2 = cachedev;
  84. if (!_stricmp(data, "discid") || !_stricmp(data, "cddbid"))
  85. {
  86. dest[0] = 0;
  87. #ifdef DISCID
  88. DiscId *disc = discid_new();
  89. wchar_t drive[4] = {device, L':'};
  90. if (!discid_read_sparse(disc, drive, 0)) {
  91. discid_free(disc);
  92. return 0;
  93. }
  94. if (!_stricmp(data, "cddbid"))
  95. lstrcpynW(dest, AutoWide(discid_get_freedb_id(disc)), destlen);
  96. else
  97. lstrcpynW(dest, AutoWide(discid_get_id(disc)), destlen);
  98. discid_free(disc);
  99. #endif
  100. }
  101. else if (!_stricmp(data, "cdengine"))
  102. {
  103. dest[0] = 0;
  104. if (g_cdplay && device && g_cdplay->IsPlaying(device))
  105. {
  106. if (g_cdplay == daePlayer)
  107. lstrcpynW(dest, L"DAE", destlen);
  108. else if (g_cdplay == windacPlayer)
  109. {
  110. if (hDLL)
  111. lstrcpynW(dest, L"ASPI", destlen);
  112. else
  113. lstrcpynW(dest, L"SPTI", destlen);
  114. }
  115. else if (g_cdplay == mciPlayer)
  116. lstrcpynW(dest, L"MCI", destlen);
  117. }
  118. return 1;
  119. }
  120. else if (!_stricmp(data, "<begin>"))
  121. {
  122. if (!CDOpen(&cachedev, device, L"cache"))
  123. cachedev = 0;
  124. if (NULL != dest && destlen > 1)
  125. {
  126. dest[0] = (NULL != cachedev) ? L'1' : L'0';
  127. dest[1] = L'\0';
  128. }
  129. cachedev_used = 1;
  130. //OutputDebugString("begin device caching\n");
  131. }
  132. else if (!_stricmp(data, "<end>"))
  133. {
  134. if (cachedev_used && cachedev)
  135. CDClose(&cachedev);
  136. //OutputDebugString("end device caching\n");
  137. cachedev_used = 0;
  138. cachedev = 0;
  139. }
  140. else if (!_stricmp(data, "<eject>"))
  141. {
  142. if (!cachedev_used)
  143. {
  144. if (!CDOpen(&dev2, device, L"eject"))
  145. dev2 = 0;
  146. }
  147. if (dev2)
  148. {
  149. CDEject(dev2);
  150. if (dev2 != cachedev)
  151. CDClose(&dev2);
  152. }
  153. }
  154. else if (!_stricmp(data, "ntracks"))
  155. {
  156. if (!cachedev_used)
  157. {
  158. if (!CDOpen(&dev2, device, L"ntracks")) dev2 = 0;
  159. }
  160. if (dev2)
  161. {
  162. _itow(CDGetTracks(dev2), dest, 10);
  163. if (dev2 != cachedev) CDClose(&dev2);
  164. }
  165. else
  166. {
  167. if (NULL != dest && destlen > 1)
  168. {
  169. dest[0] = L'0';
  170. dest[1] = L'\0';
  171. }
  172. }
  173. }
  174. else if (!_stricmp(data, "tracktype"))
  175. {
  176. if (!cachedev_used)
  177. {
  178. if (!CDOpen(&dev2, device, L"tracktype")) dev2 = 0;
  179. }
  180. if (dev2)
  181. {
  182. MCI_STATUS_PARMS sMCIStatus;
  183. sMCIStatus.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
  184. sMCIStatus.dwTrack = track;
  185. if (mciSendCommand(dev2, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR) &sMCIStatus))
  186. WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN,dest,destlen);
  187. else lstrcpynW(dest, (sMCIStatus.dwReturn != MCI_CDA_TRACK_AUDIO ? L"data" : L"audio"), destlen);
  188. if (dev2 != cachedev) CDClose(&dev2);
  189. }
  190. }
  191. else if (!_stricmp(data, "length"))
  192. {
  193. if (!cachedev_used)
  194. {
  195. if (!CDOpen(&dev2, device, L"length")) dev2 = 0;
  196. }
  197. if (dev2)
  198. {
  199. MCI_SET_PARMS sMCISet;
  200. sMCISet.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
  201. MCISendCommand(dev2, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet);
  202. _itow(CDGetTrackLength(dev2, track), dest, 10);
  203. sMCISet.dwTimeFormat = MCI_FORMAT_TMSF;
  204. MCISendCommand(dev2, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet);
  205. if (dev2 != cachedev)
  206. CDClose(&dev2);
  207. }
  208. }
  209. else if (!_stricmp(data, "album") || !_stricmp(data, "artist") ||
  210. !_stricmp(data, "year") || !_stricmp(data, "genre") ||
  211. !_stricmp(data, "title") || !_stricmp(data, "comment") ||
  212. !_stricmp(data, "tuid") || !_stricmp(data, "albumartist") ||
  213. !_stricmp(data, "publisher") || !_stricmp(data, "disc") ||
  214. !_stricmp(data, "conductor") || !_stricmp(data, "composer") ||
  215. !_stricmp(data, "remixing") || !_stricmp(data, "isrc") ||
  216. !_stricmp(data, "GracenoteFileID") || !_stricmp(data, "GracenoteExtData")
  217. )
  218. {
  219. int cached = 0;
  220. //cache our myps
  221. static DINFO myps;
  222. /*static unsigned int last_time;
  223. unsigned int now = GetTickCount();*/
  224. cached = !_wcsnicmp(fn, last_fn, 7);
  225. // TODO disabled as this is causing more access issues than it seems to help...
  226. /*if (cached)
  227. {
  228. if (now > last_time + 1000) cached = 0;
  229. if (now < last_time - 1000) cached = 0; // counter wrapped
  230. }*/
  231. if (!cached)
  232. {
  233. lstrcpynW(last_fn, fn, 8);
  234. memset(&myps, 0, sizeof(myps));
  235. if (!cachedev_used)
  236. {
  237. if (CDOpen(&dev2, device, L"extinfo"))
  238. {
  239. GetDiscID(dev2, &myps);
  240. CDClose(&dev2);
  241. }
  242. }
  243. else GetDiscID(dev2, &myps);
  244. }
  245. if (myps.CDDBID)
  246. {
  247. // try to get CDDB information and then revert to CD-Text if CDDB is not available
  248. if (GetCDDBInfo(&myps, device))
  249. {
  250. wchar_t cache[] = {L"cda://x"};
  251. cache[6] = device;
  252. PostMessage(line.hMainWindow, WM_WA_IPC, (WPARAM)cache, IPC_REFRESHPLCACHE);
  253. }
  254. else if (!cached && !myps.populated)
  255. {
  256. if (DoCDText(&myps, device))
  257. {
  258. wchar_t cache[] = {L"cda://x"};
  259. cache[6] = device;
  260. PostMessage(line.hMainWindow, WM_WA_IPC, (WPARAM)cache, IPC_REFRESHPLCACHE);
  261. }
  262. }
  263. if (!_stricmp(data, "album"))
  264. {
  265. if (myps.title)
  266. lstrcpynW(dest, myps.title, destlen);
  267. else
  268. dest[0]=0;
  269. }
  270. else if (!_stricmp(data, "artist") && track>0 && track<100)
  271. {
  272. if (myps.tracks[track-1].artist)
  273. lstrcpynW(dest, myps.tracks[track-1].artist, destlen);
  274. else if (myps.artist)
  275. lstrcpynW(dest, myps.artist, destlen);
  276. else
  277. dest[0]=0;
  278. }
  279. else if (!_stricmp(data, "albumartist"))
  280. {
  281. if (myps.artist)
  282. lstrcpynW(dest, myps.artist, destlen);
  283. else if (track == 0)
  284. WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN_ARTIST,dest,destlen);
  285. else
  286. dest[0]=0;
  287. }
  288. else if (!_stricmp(data, "title") && track>0 && track<100)
  289. {
  290. if (myps.tracks[track-1].title)
  291. lstrcpynW(dest, myps.tracks[track-1].title, destlen);
  292. else
  293. StringCchPrintfW(dest, destlen, WASABI_API_LNGSTRINGW(IDS_TRACK_X), track);
  294. }
  295. else if (!_stricmp(data, "year"))
  296. {
  297. if (myps.year)
  298. lstrcpynW(dest, myps.year, destlen);
  299. else
  300. dest[0]=0;
  301. }
  302. else if (!_stricmp(data, "genre"))
  303. {
  304. if (myps.genre)
  305. lstrcpynW(dest, myps.genre, destlen);
  306. else
  307. dest[0]=0;
  308. }
  309. else if (!_stricmp(data, "comment"))
  310. {
  311. if (myps.notes)
  312. lstrcpynW(dest, myps.notes, destlen);
  313. else
  314. dest[0]=0;
  315. }
  316. else if (!_stricmp(data, "publisher"))
  317. {
  318. if (myps.label)
  319. lstrcpynW(dest, myps.label, destlen);
  320. else
  321. dest[0]=0;
  322. }
  323. else if (!_stricmp(data, "composer"))
  324. {
  325. if (track>0 && myps.tracks[track-1].composer)
  326. lstrcpynW(dest, myps.tracks[track-1].composer, destlen);
  327. else if (myps.composer)
  328. lstrcpynW(dest, myps.composer, destlen);
  329. else
  330. dest[0]=0;
  331. }
  332. else if (!_stricmp(data, "remixing"))
  333. {
  334. if (track>0 && myps.tracks[track-1].remixing)
  335. lstrcpynW(dest, myps.tracks[track-1].remixing, destlen);
  336. else if (myps.composer)
  337. lstrcpynW(dest, myps.remixing, destlen);
  338. else
  339. dest[0]=0;
  340. }
  341. else if (!_stricmp(data, "conductor"))
  342. {
  343. if (track>0 && myps.tracks[track-1].conductor)
  344. lstrcpynW(dest, myps.tracks[track-1].conductor, destlen);
  345. else if (myps.conductor)
  346. lstrcpynW(dest, myps.conductor, destlen);
  347. else
  348. dest[0]=0;
  349. }
  350. else if (!_stricmp(data, "isrc") && track>0 && track<100)
  351. {
  352. if (myps.tracks[track-1].isrc)
  353. lstrcpynW(dest, myps.tracks[track-1].isrc, destlen);
  354. else
  355. dest[0]=0;
  356. }
  357. else if (!_stricmp(data, "GracenoteFileID") && track>0 && track<100)
  358. {
  359. if (myps.tracks[track-1].tagID)
  360. lstrcpynW(dest, myps.tracks[track-1].tagID, destlen);
  361. else
  362. dest[0]=0;
  363. }
  364. else if (!_stricmp(data, "GracenoteExtData") && track>0 && track<100)
  365. {
  366. if (myps.tracks[track-1].extData)
  367. lstrcpynW(dest, myps.tracks[track-1].extData, destlen);
  368. else
  369. dest[0]=0;
  370. }
  371. else if (!_stricmp(data, "tuid"))
  372. {
  373. if (myps.tuid)
  374. lstrcpynW(dest, myps.tuid, destlen);
  375. else
  376. dest[0]=0;
  377. }
  378. else if (!_stricmp(data, "disc"))
  379. {
  380. if (myps.numdiscs > 0)
  381. StringCchPrintf(dest, destlen, L"%u/%u", myps.discnum, myps.numdiscs);
  382. else if (myps.discnum)
  383. StringCchPrintf(dest, destlen, L"%u", myps.discnum);
  384. else
  385. dest[0] = 0;
  386. }
  387. else
  388. {
  389. // last_time = GetTickCount();
  390. return 0;// some error condition (such as track == 0) got us here
  391. }
  392. }
  393. else
  394. {
  395. if (!_stricmp(data, "title") && track>0 && track<100)
  396. {
  397. StringCchPrintfW(dest, destlen, WASABI_API_LNGSTRINGW(IDS_TRACK_X), track);
  398. }
  399. last_fn[0] = 0x00;
  400. }
  401. // last_time = GetTickCount();
  402. }
  403. else if (!_stricmp(data, "cdtype"))
  404. {
  405. dest[0] = 0;
  406. #ifndef IGNORE_API_GRACENOTE
  407. DWORD retCode = PRIMOSDK_OK + 1;
  408. obj_primo *primo=0;
  409. waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid());
  410. if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface());
  411. if (primo)
  412. {
  413. DWORD unit = (DWORD)fn[6];
  414. DWORD mediumtype;
  415. DWORD mediumformat;
  416. DWORD erasable;
  417. DWORD tracks, used, free;
  418. retCode = primo->DiscInfo(&unit, &mediumtype, &mediumformat, &erasable, &tracks, &used, &free);
  419. if (retCode == PRIMOSDK_OK)
  420. {
  421. if (mediumformat > 0xf0 && mediumformat < 0xff) lstrcpynW(dest, L"DVD", destlen);
  422. else lstrcpynW(dest, L"CD", destlen);
  423. if (mediumtype == PRIMOSDK_BLANK || mediumtype == PRIMOSDK_COMPLIANTGOLD) StringCchCatW(dest, destlen, L"R");
  424. if (erasable) StringCchCatW(dest, destlen, L"W");
  425. }
  426. sf->releaseInterface(primo);
  427. }
  428. return (retCode == PRIMOSDK_OK);
  429. #else
  430. return 0;
  431. #endif
  432. }
  433. else if (!_stricmp(data, "cdtype2"))
  434. {
  435. dest[0] = 0;
  436. #ifndef IGNORE_API_GRACENOTE
  437. DWORD retCode = PRIMOSDK_OK + 1;
  438. obj_primo *primo=0;
  439. waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid());
  440. if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface());
  441. if (primo)
  442. {
  443. DWORD unit = (DWORD)fn[6];
  444. DWORD mediumType;
  445. DWORD mediumFormat;
  446. DWORD erasable;
  447. DWORD tracks, used, free;
  448. DWORD medium = -1, protectedDVD = -1, mediumEx = -1;
  449. DWORD rfu;
  450. retCode = primo->DiscInfoEx(&unit, 1, &mediumType, &mediumFormat, &erasable, &tracks, &used, &free);
  451. if (retCode == PRIMOSDK_OK)
  452. {
  453. primo->DiscInfo2(&unit, &medium, &protectedDVD, NULL, &mediumEx, &rfu);
  454. //format: mediumType;mediumFormat;mediumEx;protectedDVD;erasable;tracks;used;free
  455. StringCchPrintfW(dest, destlen, L"%d;%d;%d;%d;%d;%d;%d;%d", mediumType, mediumFormat, mediumEx, protectedDVD, erasable, tracks, used, free);
  456. }
  457. sf->releaseInterface(primo);
  458. }
  459. return (retCode == PRIMOSDK_OK);
  460. #else
  461. return 0;
  462. #endif
  463. }
  464. else if (!_stricmp(data, "cdlengths"))
  465. {
  466. dest[0] = 0;
  467. #ifndef IGNORE_API_GRACENOTE
  468. obj_primo *primo=0;
  469. waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid());
  470. if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface());
  471. if (primo)
  472. {
  473. DWORD unit = (DWORD)fn[6];
  474. DWORD mediumtype;
  475. DWORD mediumformat;
  476. DWORD erasable;
  477. DWORD tracks, used, free;
  478. if (primo->DiscInfo(&unit, &mediumtype, &mediumformat, &erasable, &tracks, &used, &free) == PRIMOSDK_OK)
  479. {
  480. StringCchPrintfW(dest, destlen, L"%d,%d", free, used);
  481. }
  482. sf->releaseInterface(primo);
  483. }
  484. #endif
  485. }
  486. else if (!_stricmp(data, "cdspeeds"))
  487. {
  488. dest[0] = 0;
  489. #ifndef IGNORE_API_GRACENOTE
  490. DWORD retCode = PRIMOSDK_OK + 1;
  491. obj_primo *primo=0;
  492. waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid());
  493. if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface());
  494. if (primo)
  495. {
  496. DWORD unit = (DWORD)fn[6];
  497. DWORD cdspeeds[32];
  498. DWORD dvdspeeds[32];
  499. DWORD capabilities;
  500. retCode = primo->UnitSpeeds(&unit, (unsigned long *) & cdspeeds, (unsigned long *) & dvdspeeds, &capabilities);
  501. if (retCode == PRIMOSDK_OK)
  502. {
  503. wchar_t *p = dest;
  504. //reading speeds
  505. int i;
  506. for (i = 0;cdspeeds[i] != 0xFFFFFFFF;i++);
  507. i++;
  508. //CD-R speeds
  509. for (;cdspeeds[i] != 0xFFFFFFFF;i++)
  510. {
  511. StringCchPrintfW(p, destlen, L"%d", cdspeeds[i]);
  512. StringCchCatW(p, destlen, L"/");
  513. p += lstrlenW(p);
  514. }
  515. *p = ';';
  516. p++;
  517. i++;
  518. //CD-RW speeds
  519. for (;cdspeeds[i] != 0xFFFFFFFF;i++)
  520. {
  521. StringCchPrintfW(p, destlen, L"%d", cdspeeds[i]);
  522. StringCchCatW(p, destlen, L"/");
  523. p += lstrlenW(p);
  524. }
  525. }
  526. sf->releaseInterface(primo);
  527. }
  528. return (retCode == PRIMOSDK_OK);
  529. #else
  530. return 0;
  531. #endif
  532. }
  533. else if (!_stricmp(data, "cdinfo"))
  534. {
  535. dest[0] = 0;
  536. #ifndef IGNORE_API_GRACENOTE
  537. DWORD retCode = PRIMOSDK_OK + 1;
  538. obj_primo *primo=0;
  539. waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid());
  540. if (sf) primo = reinterpret_cast<obj_primo *>(sf->getInterface());
  541. if (primo)
  542. {
  543. DWORD unit = (DWORD)fn[6];
  544. DWORD type;
  545. BYTE szUnitDescr[64 + 1] = {0,}; // Unit Vendor, Model and FW. version
  546. retCode = primo->UnitInfo(&unit, &type, szUnitDescr, NULL);
  547. if (retCode == PRIMOSDK_OK)
  548. {
  549. StringCchPrintfW(dest, destlen, L"%d;%s", type, (wchar_t *)AutoWide((char *)szUnitDescr));
  550. }
  551. sf->releaseInterface(primo);
  552. }
  553. return (retCode == PRIMOSDK_OK);
  554. #else
  555. return 0;
  556. #endif
  557. }
  558. else if (!_stricmp(data, "cdlock"))
  559. {
  560. dest[0] = 0;
  561. #ifndef IGNORE_API_GRACENOTE
  562. if (!m_veritas_handle)
  563. {
  564. waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid());
  565. if (sf) m_veritas_handle = reinterpret_cast<obj_primo *>(sf->getInterface());
  566. }
  567. if (!m_veritas_handle)
  568. return 0;
  569. m_nblock++;
  570. DWORD unit = (DWORD)fn[6];
  571. m_veritas_handle->UnitLock(&unit, PRIMOSDK_LOCK);
  572. lstrcpynW(dest, L"locked", destlen);
  573. return 1;
  574. #else
  575. return 0;
  576. #endif
  577. }
  578. else if (!_stricmp(data, "cdunlock"))
  579. {
  580. if (!m_nblock) return 0;
  581. #ifndef IGNORE_API_GRACENOTE
  582. if (!m_veritas_handle)
  583. {
  584. waServiceFactory *sf = line.service->service_getServiceByGuid(obj_primo::getServiceGuid());
  585. if (sf) m_veritas_handle = reinterpret_cast<obj_primo *>(sf->getInterface());
  586. }
  587. if (!m_veritas_handle)
  588. return 0;
  589. DWORD unit = (DWORD)fn[6];
  590. m_veritas_handle->UnitLock(&unit, PRIMOSDK_UNLOCK);
  591. m_nblock--;
  592. lstrcpynW(dest, L"unlocked", destlen);
  593. return 1;
  594. #else
  595. return 0;
  596. #endif
  597. }
  598. else if (!_stricmp(data, "track") && track)
  599. {
  600. StringCchPrintfW(dest, destlen, L"%d", track);
  601. return 1;
  602. }
  603. else if (!_stricmp(data, "bitrate") && track)
  604. {
  605. StringCchPrintfW(dest, destlen, L"%d", 1411/*200*/);
  606. return 1;
  607. }
  608. else
  609. return 0;
  610. return 1;
  611. }
  612. return 0;
  613. }
  614. static wchar_t m_eiw_lastdrive;
  615. //#ifndef IGNORE_API_GRACENOTE
  616. static DINFO setInfo;
  617. //#endif
  618. void ParseIntSlashInt(const wchar_t *string, int *part, int *parts);
  619. extern "C" __declspec(dllexport) int winampSetExtendedFileInfoW(const wchar_t *fn, const char *data, wchar_t *val)
  620. {
  621. //#ifndef IGNORE_API_GRACENOTE
  622. s_last_error = NULL;
  623. if (!lstrcmpiW(PathFindExtensionW(fn), L".cda") && !_wcsnicmp(fn + 1, L":\\track", 7)) // stupid hack, converts x:\\trackXX.cda to cda://x,XX
  624. {
  625. static wchar_t fakebuf[128];
  626. StringCchPrintf(fakebuf, 128, L"cda://%c,%d", fn[0], _wtoi(PathFindFileNameW(fn) + 5));
  627. fn = fakebuf;
  628. }
  629. wchar_t drive = 0;
  630. int tracknum = -1;
  631. if (!ParseName(fn, drive, tracknum))
  632. return 0;
  633. if (drive < 'A' || drive > 'Z') return 0;
  634. if (drive != m_eiw_lastdrive)
  635. {
  636. setInfo.Reset();
  637. setInfo.populated=false;
  638. m_eiw_lastdrive = 0;
  639. MCIDEVICEID dev2 = 0;
  640. if (!CDOpen(&dev2, drive, L"setinfo")) dev2 = 0;
  641. if (dev2)
  642. {
  643. int ret = GetDiscID(dev2, &setInfo);
  644. CDClose(&dev2);
  645. if (!ret)
  646. {
  647. GetCDDBInfo(&setInfo, drive);
  648. m_eiw_lastdrive = drive;
  649. }
  650. }
  651. }
  652. if (!m_eiw_lastdrive)
  653. return 0;
  654. #define DO_TRACK(comparetag, field) if (tracknum > 0 && tracknum < 100 && !_stricmp(data, comparetag)) {\
  655. ndestring_release(setInfo.tracks[tracknum-1]. ## field);\
  656. setInfo.tracks[tracknum-1]. ## field=0;\
  657. if (val && *val) setInfo.tracks[tracknum-1]. ## field=ndestring_wcsdup(val);\
  658. }
  659. #define DO_DISC(comparetag, field) if (!_stricmp(data, comparetag)) {\
  660. ndestring_release(setInfo. ## field);\
  661. setInfo. ## field=0;\
  662. if (val && *val) setInfo. ## field=ndestring_wcsdup(val);\
  663. }
  664. if (tracknum > 0 && tracknum < 100 && !_stricmp(data, "artist"))
  665. {
  666. if (val && setInfo.tracks[tracknum-1].artist == 0 && setInfo.artist && !_wcsicmp(setInfo.artist, val))
  667. val=0;
  668. ndestring_release(setInfo.tracks[tracknum-1].artist);
  669. setInfo.tracks[tracknum-1].artist=0;
  670. if (val && *val) setInfo.tracks[tracknum-1].artist=ndestring_wcsdup(val);
  671. }
  672. else DO_TRACK("title", title)
  673. else DO_TRACK("composer", composer)
  674. else DO_TRACK("conductor", conductor)
  675. else DO_TRACK("GracenoteFileID", tagID)
  676. else DO_TRACK("GracenoteExtData", extData)
  677. else DO_DISC("album", title)
  678. else DO_DISC("albumartist", artist)
  679. else DO_DISC("genre", genre)
  680. else DO_DISC("year", year)
  681. else DO_DISC("comment", notes)
  682. else DO_DISC("publisher", label)
  683. else DO_DISC("tuid", tuid)
  684. else DO_DISC("composer", composer)
  685. else DO_DISC("conductor", conductor)
  686. else if (!_stricmp(data, "disc"))
  687. ParseIntSlashInt(val , &setInfo.discnum, &setInfo.numdiscs);
  688. else
  689. //#endif
  690. return 0;
  691. return 1;
  692. }
  693. extern "C" __declspec(dllexport) int winampWriteExtendedFileInfo()
  694. {
  695. s_last_error = NULL;
  696. // write it out
  697. if (m_eiw_lastdrive)
  698. {
  699. //#ifndef IGNORE_API_GRACENOTE
  700. CddbCache_SetDisc(&setInfo, S_OK);
  701. StoreDINFO(setInfo.CDDBID, &setInfo);
  702. m_eiw_lastdrive = 0;
  703. last_fn[0]=0;
  704. if (cachedev_used)
  705. {
  706. CDClose(&cachedev);
  707. cachedev_used=0;
  708. }
  709. return 1;
  710. //#endif
  711. }
  712. return 0;
  713. }
  714. // return 1 if you want winamp to show it's own file info dialogue, 0 if you want to show your own (via In_Module.InfoBox)
  715. // if returning 1, remember to implement winampGetExtendedFileInfo("formatinformation")!
  716. extern "C" __declspec(dllexport) int winampUseUnifiedFileInfoDlg(const wchar_t * fn)
  717. {
  718. return 1;
  719. }
  720. #define SET_IF(hwndDlg, id, data) if (data) SetDlgItemText(hwndDlg, id, data); else SetDlgItemText(hwndDlg, id, L"");
  721. static void Fill(HWND hwndDlg, const DINFO *info)
  722. {
  723. SET_IF(hwndDlg, IDC_TITLE, info->title);
  724. SET_IF(hwndDlg, IDC_ARTIST, info->artist);
  725. if (info->discnum)
  726. SetDlgItemInt(hwndDlg, IDC_DISC, info->discnum, FALSE);
  727. else
  728. SetDlgItemText(hwndDlg, IDC_DISCS, L"");
  729. if (info->numdiscs)
  730. SetDlgItemInt(hwndDlg, IDC_DISCS, info->numdiscs, FALSE);
  731. else
  732. SetDlgItemText(hwndDlg, IDC_DISCS, L"");
  733. SET_IF(hwndDlg, IDC_YEAR, info->year);
  734. SET_IF(hwndDlg, IDC_LABEL, info->label);
  735. SET_IF(hwndDlg, IDC_NOTES, info->notes);
  736. SET_IF(hwndDlg, IDC_GENRE, info->genre);
  737. SendDlgItemMessage(hwndDlg, IDC_TRACKLIST, LB_RESETCONTENT, 0, 0);
  738. #ifndef IGNORE_API_GRACENOTE
  739. for (int x = 0; x < info->ntracks; x ++)
  740. {
  741. wchar_t buf[1100] = {0};
  742. if (!info->tracks[x].title)
  743. StringCchPrintfW(buf, 1100, L"%d.", x+1);
  744. else if (info->tracks[x].artist && info->tracks[x].artist[0] && wcscmp(info->tracks[x].artist, info->artist))
  745. StringCchPrintfW(buf, 1100, L"%d. %s - %s", x+1, info->tracks[x].artist, info->tracks[x].title);
  746. else
  747. StringCchPrintfW(buf, 1100, L"%d. %s", x+1, info->tracks[x].title);
  748. SendDlgItemMessageW(hwndDlg, IDC_TRACKLIST, LB_ADDSTRING, 0, (LPARAM)buf);
  749. }
  750. #endif
  751. }
  752. #ifndef IGNORE_API_GRACENOTE
  753. struct LookupData
  754. {
  755. LookupData(HWND hwndDlg)
  756. {
  757. hwnd=hwndDlg;
  758. dlgItem=0;
  759. device=0;
  760. tracknum=0;
  761. use=false;
  762. disc=0;
  763. memset(szTOC, 0, sizeof(szTOC));
  764. }
  765. ~LookupData()
  766. {
  767. if (disc)
  768. disc->Release();
  769. }
  770. HWND hwnd;
  771. int dlgItem;
  772. wchar_t szTOC[2048];
  773. char device;
  774. int tracknum;
  775. bool use;
  776. ICddbDisc *disc;
  777. DINFO info;
  778. };
  779. static HRESULT CALLBACK Cddb_LookupCallback(HRESULT result, ICddbDisc *pDisc, DWORD *pdwAutoCloseDelay, ULONG_PTR user)
  780. {
  781. LookupData *data = (LookupData *)user;
  782. if (S_OK == result)
  783. {
  784. data->info.Reset();
  785. data->info.populated=false;
  786. if (data->disc)
  787. data->disc->Release();
  788. data->disc=pDisc;
  789. data->disc->AddRef();
  790. GetDiscInfo(pDisc, &data->info);
  791. Fill(data->hwnd, &data->info);
  792. ICddbCacheManager* pCache;
  793. HRESULT hr = Cddb_GetICacheManger((void**)&pCache);
  794. if (SUCCEEDED(hr))
  795. {
  796. pCache->StoreDiscByToc(data->szTOC, data->disc);
  797. pCache->Release();
  798. }
  799. }
  800. else
  801. {
  802. *pdwAutoCloseDelay = AUTOCLOSE_NEVER;
  803. }
  804. return S_OK;
  805. }
  806. static HRESULT CALLBACK Cddb_EditCallback(HRESULT result, ICddbDisc *pDisc, DWORD *pdwAutoCloseDelay, ULONG_PTR user)
  807. {
  808. LookupData *data = (LookupData *)user;
  809. if (FAILED(result))
  810. {
  811. *pdwAutoCloseDelay = AUTOCLOSE_NEVER;
  812. return S_OK;
  813. }
  814. if (SUCCEEDED(result))
  815. {
  816. HRESULT hr(S_OK);
  817. ICDDBControl *pControl;
  818. CDDBUIFlags uiFlags = UI_EDITMODE;
  819. if (SUCCEEDED(hr)) hr = Cddb_GetIControl((void**)&pControl);
  820. if (SUCCEEDED(hr))
  821. {
  822. if (!pDisc)
  823. {
  824. uiFlags = UI_SUBMITNEW;
  825. hr = pControl->GetSubmitDisc(data->szTOC, 0, 0, &pDisc);
  826. if (FAILED(hr)) pDisc = NULL;
  827. }
  828. else
  829. pDisc->AddRef();
  830. if (pDisc)
  831. {
  832. HWND parent = GetParent(data->hwnd);
  833. Cddb_DisplayDiscInfo(pDisc, &uiFlags, parent);
  834. if (uiFlags & UI_DATA_CHANGED)
  835. {
  836. ICddbCacheManager* pCache;
  837. hr = Cddb_GetICacheManger((void**)&pCache);
  838. if (SUCCEEDED(hr))
  839. {
  840. pCache->StoreDiscByToc(data->szTOC, pDisc);
  841. pCache->Release();
  842. }
  843. data->info.Reset();
  844. data->info.populated=false;
  845. if (data->disc)
  846. data->disc->Release();
  847. data->disc=pDisc;
  848. data->disc->AddRef();
  849. GetDiscInfo(pDisc, &data->info);
  850. Fill(data->hwnd, &data->info);
  851. }
  852. pDisc->Release();
  853. }
  854. pControl->Release();
  855. }
  856. }
  857. return S_OK;
  858. }
  859. bool SubmitEdit(ICddbDisc *pDisc)
  860. {
  861. //CDDBUIFlags uiFlags = UI_EDITMODE;
  862. ICDDBControl *pControl;
  863. HRESULT hr = Cddb_GetIControl((void**)&pControl);
  864. if (SUCCEEDED(hr))
  865. {
  866. long val;
  867. pControl->SubmitDisc(pDisc, 0, &val);
  868. pControl->Release();
  869. if (val == 0)
  870. return true;
  871. }
  872. return false;
  873. }
  874. #endif
  875. #define SEND_DISC(field, val) SendMessage(hwndParent,WM_USER, (WPARAM)field,(LPARAM)(val?val:L""));
  876. #define SEND_DISC_OR_TRACK(field, disc_val, track_val) { if (track_val) SendMessage(hwndParent,WM_USER, (WPARAM)field,(LPARAM)track_val); else if (disc_val) SendMessage(hwndParent,WM_USER, (WPARAM)field,(LPARAM)disc_val); else SendMessage(hwndParent,WM_USER, (WPARAM)field,(LPARAM)L"");}
  877. #define SEND_TRACK(field, val) SendMessage(hwndParent,WM_USER, (WPARAM)field,(LPARAM)(val?val:L""));
  878. #ifndef IGNORE_API_GRACENOTE
  879. static void NotifyParent_MusicID(HWND hwndParent, const LookupData *data)
  880. {
  881. DINFO disc = data->info;
  882. TRACKINFO dummy;
  883. TRACKINFO &track = data->tracknum?disc.tracks[data->tracknum-1]:dummy;
  884. SEND_DISC(L"album", disc.title);
  885. SEND_DISC(L"albumartist", disc.artist);
  886. SEND_DISC_OR_TRACK(L"artist", disc.artist, track.artist);
  887. SEND_DISC(L"tuid", disc.tuid);
  888. SEND_DISC(L"year", disc.year);
  889. SEND_DISC(L"genre", disc.genre);
  890. SEND_DISC(L"publisher", disc.label);
  891. SEND_DISC(L"comment", disc.notes);
  892. SEND_DISC_OR_TRACK(L"conductor", disc.conductor, track.conductor);
  893. SEND_DISC_OR_TRACK(L"composer", disc.composer, track.composer);
  894. wchar_t disc_temp[64] = {0};
  895. if (disc.numdiscs)
  896. StringCchPrintfW(disc_temp, 64, L"%d/%d", disc.discnum, disc.numdiscs);
  897. else if (disc.discnum)
  898. StringCchPrintfW(disc_temp, 64, L"%d", disc.discnum);
  899. else
  900. disc_temp[0]=0;
  901. SEND_DISC(L"disc", disc_temp);
  902. SEND_TRACK(L"title", track.title);
  903. SEND_TRACK(L"GracenoteFileID", track.tagID);
  904. SEND_TRACK(L"GracenoteExtData", track.extData);
  905. }
  906. static INT_PTR CALLBACK MusicID_Proc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  907. {
  908. switch (msg)
  909. {
  910. case WM_INITDIALOG:
  911. {
  912. LookupData *data = new LookupData(hwndDlg);
  913. wchar_t *filename = (wchar_t *)lParam;
  914. if (ParseName(AutoChar(filename), data->device, data->tracknum)) // TODO: remove AutoChar here, I'm just being lazy
  915. {
  916. MCIDEVICEID d = 0;
  917. if (CDOpen(&d, data->device, L"MusicID_Dlg"))
  918. {
  919. GetDiscID(d, &data->info);
  920. CDClose(&d);
  921. if (Cddb_CalculateTOC(&data->info, data->szTOC, sizeof(data->szTOC)/sizeof(wchar_t)))
  922. {
  923. ICddbCacheManager *pCache;
  924. if (SUCCEEDED(Cddb_GetICacheManger((void**)&pCache)))
  925. {
  926. if (SUCCEEDED(pCache->FetchDiscByToc(data->szTOC, &data->disc)))
  927. {
  928. GetDiscInfo(data->disc, &data->info);
  929. Fill(hwndDlg, &data->info);
  930. }
  931. pCache->Release();
  932. }
  933. }
  934. }
  935. }
  936. SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)data);
  937. }
  938. break;
  939. case WM_COMMAND:
  940. switch (LOWORD(wParam))
  941. {
  942. case IDOK:
  943. {
  944. LookupData *data = (LookupData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  945. if (data->use && data->disc)
  946. {
  947. StoreDisc(data->info.CDDBID, data->disc);
  948. CddbCache_SetDisc(&data->info, S_OK);
  949. }
  950. }
  951. break;
  952. case IDC_LOOKUP:
  953. {
  954. LookupData *data = (LookupData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  955. if (data)
  956. {
  957. data->dlgItem = LOWORD(wParam);
  958. HWND parent = GetParent(hwndDlg);
  959. UINT flags = CDDB_NOCACHE | CDDB_UI_MODAL | CDDB_UI_MULTIPLE | CDDB_UI_RESULT_MODAL;
  960. HRESULT hr = Cddb_DoLookup(data->szTOC, parent, Cddb_LookupCallback, flags, (ULONG_PTR)data);
  961. if (FAILED(hr)) Cddb_DisplayResultDlg(parent, hr, AUTOCLOSE_NEVER, flags);
  962. }
  963. }
  964. break;
  965. case IDC_USE:
  966. {
  967. LookupData *data = (LookupData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  968. data->use=true;
  969. NotifyParent_MusicID(GetParent(hwndDlg), data);
  970. }
  971. break;
  972. case IDC_EDIT_GRACENOTE:
  973. {
  974. LookupData *data = (LookupData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  975. data->dlgItem = LOWORD(wParam);
  976. HWND parent = GetParent(hwndDlg);
  977. UINT flags = CDDB_UI_MODAL | CDDB_UI_MULTIPLE | CDDB_UI_RESULT_MODAL;
  978. HRESULT hr = Cddb_DoLookup(data->szTOC, parent, Cddb_EditCallback, flags, (ULONG_PTR)data);
  979. if (FAILED(hr)) Cddb_DisplayResultDlg(parent, hr, AUTOCLOSE_NEVER, flags);
  980. }
  981. break;
  982. case IDC_SUBMIT:
  983. {
  984. LookupData *data = (LookupData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  985. if (data && data->disc)
  986. SubmitEdit(data->disc);
  987. }
  988. break;
  989. }
  990. break;
  991. case WM_DESTROY:
  992. {
  993. LookupData *data = (LookupData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  994. delete data;
  995. SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)0);
  996. }
  997. break;
  998. }
  999. return 0;
  1000. }
  1001. #endif
  1002. struct CDTextData
  1003. {
  1004. public:
  1005. CDTextData()
  1006. {
  1007. device=0;
  1008. tracknum=0;
  1009. use=false;
  1010. }
  1011. DINFO info;
  1012. wchar_t device;
  1013. int tracknum;
  1014. bool use;
  1015. };
  1016. static void Send_CDText(HWND hwndParent, const CDTextData *data)
  1017. {
  1018. DINFO disc = data->info;
  1019. TRACKINFO dummy;
  1020. TRACKINFO &track = data->tracknum ? disc.tracks[data->tracknum-1] : dummy;
  1021. SEND_DISC(L"album", disc.title);
  1022. SEND_DISC(L"albumartist", disc.artist);
  1023. SEND_DISC_OR_TRACK(L"artist", disc.artist, track.artist);
  1024. SEND_DISC_OR_TRACK(L"composer", disc.composer, track.composer);
  1025. SEND_TRACK(L"title", track.title);
  1026. SEND_DISC_OR_TRACK(L"genre", disc.genre, track.genre);
  1027. }
  1028. static void FillDialog_CDText(HWND hwndDlg, const DINFO &info)
  1029. {
  1030. SET_IF(hwndDlg, IDC_ARTIST, info.artist);
  1031. SET_IF(hwndDlg, IDC_ALBUM, info.title);
  1032. SET_IF(hwndDlg, IDC_COMPOSER, info.composer);
  1033. W_ListView listview(GetDlgItem(hwndDlg, IDC_TRACKS));
  1034. listview.Clear();
  1035. for (int i=0;i<info.ntracks;i++)
  1036. {
  1037. const TRACKINFO &track = info.tracks[i];
  1038. wchar_t num[64] = {0};
  1039. StringCchPrintfW(num, 64, L"%d", i+1);
  1040. int index = listview.AppendItem(num, 0);
  1041. if (track.artist)
  1042. listview.SetItemText(index, 1, track.artist);
  1043. if (track.title)
  1044. listview.SetItemText(index, 2, track.title);
  1045. if (track.genre)
  1046. listview.SetItemText(index, 3, track.genre);
  1047. if (track.composer)
  1048. listview.SetItemText(index, 4, track.composer);
  1049. }
  1050. }
  1051. static INT_PTR CALLBACK CDText_Proc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  1052. {
  1053. switch (msg)
  1054. {
  1055. case WM_INITDIALOG:
  1056. {
  1057. W_ListView listview;
  1058. listview.setwnd(GetDlgItem(hwndDlg, IDC_TRACKS));
  1059. listview.AddCol(WASABI_API_LNGSTRINGW(IDS_TRACK), 50);
  1060. listview.AddCol(WASABI_API_LNGSTRINGW(IDS_ARTIST), 150);
  1061. listview.AddCol(WASABI_API_LNGSTRINGW(IDS_TITLE), 150);
  1062. // TODO
  1063. listview.AddCol(L"Genre"/*WASABI_API_LNGSTRINGW(IDS_GENRE)*/, 150);
  1064. listview.AddCol(WASABI_API_LNGSTRINGW(IDS_COMPOSER), 150);
  1065. CDTextData *data = new CDTextData;
  1066. wchar_t *filename = (wchar_t *)lParam;
  1067. if (ParseName(filename, data->device, data->tracknum))
  1068. {
  1069. SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)data);
  1070. }
  1071. else
  1072. SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
  1073. // this is slow if there's no CD Text
  1074. PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_LOOKUP, BN_CLICKED), (LPARAM)GetDlgItem(hwndDlg, IDC_LOOKUP));
  1075. }
  1076. break;
  1077. case WM_COMMAND:
  1078. switch (LOWORD(wParam))
  1079. {
  1080. case IDOK:
  1081. {
  1082. CDTextData *data = (CDTextData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  1083. if (data && data->use)
  1084. StoreCDText(data->info.CDDBID, data->device);
  1085. }
  1086. break;
  1087. case IDC_LOOKUP:
  1088. {
  1089. CDTextData *data = (CDTextData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  1090. if (data && DoCDText(&data->info, data->device))
  1091. {
  1092. FillDialog_CDText(hwndDlg, data->info);
  1093. }
  1094. }
  1095. break;
  1096. case IDC_USE:
  1097. {
  1098. CDTextData *data = (CDTextData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  1099. if (data)
  1100. {
  1101. data->use=true;
  1102. Send_CDText(GetParent(hwndDlg), data);
  1103. }
  1104. }
  1105. break;
  1106. }
  1107. break;
  1108. case WM_DESTROY:
  1109. {
  1110. CDTextData *data = (CDTextData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  1111. delete data;
  1112. SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)0);
  1113. }
  1114. break;
  1115. }
  1116. return 0;
  1117. }
  1118. // should return a child window of 513x271 pixels (341x164 in msvc dlg units), or return NULL for no tab.
  1119. // Fill in name (a buffer of namelen characters), this is the title of the tab (defaults to "Advanced").
  1120. // filename will be valid for the life of your window. n is the tab number. This function will first be
  1121. // called with n == 0, then n == 1 and so on until you return NULL (so you can add as many tabs as you like).
  1122. // The window you return will recieve WM_COMMAND, IDOK/IDCANCEL messages when the user clicks OK or Cancel.
  1123. // when the user edits a field which is duplicated in another pane, do a SendMessage(GetParent(hwnd),WM_USER,(WPARAM)L"fieldname",(LPARAM)L"newvalue");
  1124. // this will be broadcast to all panes (including yours) as a WM_USER.
  1125. extern "C" __declspec(dllexport) HWND winampAddUnifiedFileInfoPane(int n, const wchar_t * filename, HWND parent, wchar_t *name, size_t namelen)
  1126. {
  1127. if (!lstrcmpiW(PathFindExtensionW(filename), L".cda") && !_wcsnicmp(filename + 1, L":\\track", 7)) // stupid hack, converts x:\\trackXX.cda to cda://x,XX
  1128. {
  1129. static wchar_t fakebuf[128];
  1130. StringCchPrintf(fakebuf, 128, L"cda://%c,%d", filename[0], _wtoi(PathFindFileNameW(filename) + 5));
  1131. filename = fakebuf;
  1132. }
  1133. #ifndef IGNORE_API_GRACENOTE
  1134. switch (n)
  1135. {
  1136. case 0: // MusicID
  1137. StringCchCopyW(name, namelen, L"MusicID"); // benski> this is purposefully not translatable
  1138. return WASABI_API_CREATEDIALOGPARAMW(IDD_MUSICID,parent,MusicID_Proc,(LPARAM)_wcsdup(filename));
  1139. case 1: // CD Text
  1140. WASABI_API_LNGSTRINGW_BUF(IDS_CDTEXT,name, namelen);
  1141. return WASABI_API_CREATEDIALOGPARAMW(IDD_CDTEXT,parent,CDText_Proc,(LPARAM)_wcsdup(filename));
  1142. default:
  1143. return 0;
  1144. }
  1145. #else
  1146. switch (n)
  1147. {
  1148. case 0: // CD Text
  1149. {
  1150. //if (DoCDText(0, filename[6])) // this is slow if there's no CD Text
  1151. {
  1152. WASABI_API_LNGSTRINGW_BUF(IDS_CDTEXT,name, namelen);
  1153. return WASABI_API_CREATEDIALOGPARAMW(IDD_CDTEXT,parent,CDText_Proc,(LPARAM)_wcsdup(filename));
  1154. }
  1155. return 0;
  1156. }
  1157. default:
  1158. return 0;
  1159. }
  1160. #endif
  1161. }