MusicID.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. #include "main.h"
  2. #include "MusicID.h"
  3. #include <vector>
  4. #include "../nu/AutoLock.h"
  5. #include <atlbase.h>
  6. #include <assert.h>
  7. #include "api__gen_ml.h"
  8. static Nullsoft::Utility::LockGuard musicIDGuard;
  9. // {113D413A-5D1F-4f4c-8AB7-5BDED46033A4}
  10. static const GUID developerConfigGroupGUID=
  11. { 0x113d413a, 0x5d1f, 0x4f4c, { 0x8a, 0xb7, 0x5b, 0xde, 0xd4, 0x60, 0x33, 0xa4 } };
  12. class MyEventHandler;
  13. #ifndef IGNORE_API_GRACENOTE
  14. static void TestAddRef(IDispatch *d)
  15. {
  16. try
  17. {
  18. ULONG l = d->AddRef();
  19. #ifdef _DEBUG
  20. char t[55] = {0};
  21. sprintf(t, "+ %p %x\n", d, l);
  22. OutputDebugStringA(t);
  23. #endif
  24. }
  25. catch(...)
  26. {
  27. }
  28. }
  29. static void TestRelease(IDispatch *d)
  30. {
  31. try
  32. {
  33. ULONG l = d->Release();
  34. #ifdef _DEBUG
  35. char t[55] = {0};
  36. sprintf(t, "- %p %x\n", d, l);
  37. OutputDebugStringA(t);
  38. #endif
  39. }
  40. catch(...)
  41. {
  42. }
  43. }
  44. static IConnectionPoint *GetConnectionPoint(IUnknown *punk, REFIID riid)
  45. {
  46. if (!punk)
  47. return 0;
  48. IConnectionPointContainer *pcpc;
  49. IConnectionPoint *pcp = 0;
  50. HRESULT hr = punk->QueryInterface(IID_IConnectionPointContainer, (void **) & pcpc);
  51. if (SUCCEEDED(hr))
  52. {
  53. pcpc->FindConnectionPoint(riid, &pcp);
  54. pcpc->Release();
  55. }
  56. punk->Release();
  57. return pcp;
  58. }
  59. // TODO: implement proper reference count so we don't leak the event handler & musicID objects
  60. static HANDLE DuplicateCurrentThread()
  61. {
  62. HANDLE fakeHandle = GetCurrentThread();
  63. HANDLE copiedHandle = 0;
  64. HANDLE processHandle = GetCurrentProcess();
  65. DuplicateHandle(processHandle, fakeHandle, processHandle, &copiedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
  66. return copiedHandle;
  67. }
  68. static HRESULT FillTag(ICddbFileInfo *info, BSTR filename)
  69. {
  70. ICddbID3TagPtr infotag = NULL;
  71. infotag.CreateInstance(CLSID_CddbID3Tag);
  72. ICddbFileTag2_5Ptr tag2_5 = NULL;
  73. infotag->QueryInterface(&tag2_5);
  74. itemRecordW *record = 0;
  75. if (AGAVE_API_MLDB)
  76. record = AGAVE_API_MLDB->GetFile(filename);
  77. if (record && infotag && tag2_5)
  78. {
  79. wchar_t itemp[64] = {0};
  80. if (record->artist)
  81. infotag->put_LeadArtist(record->artist);
  82. if (record->album)
  83. infotag->put_Album(record->album);
  84. if (record->title)
  85. infotag->put_Title(record->title);
  86. if (record->genre)
  87. infotag->put_Genre(record->genre);
  88. if (record->track > 0)
  89. infotag->put_TrackPosition(_itow(record->track, itemp, 10));
  90. // TODO: if (record->tracks > 0)
  91. if (record->year > 0)
  92. infotag->put_Year(_itow(record->year, itemp, 10));
  93. if (record->publisher)
  94. infotag->put_Label(record->publisher);
  95. /*
  96. if (GetFileInfo(filename, L"ISRC", meta, 512) && meta[0])
  97. infotag->put_ISRC(meta);
  98. */
  99. if (record->disc > 0)
  100. infotag->put_PartOfSet(_itow(record->disc, itemp, 10));
  101. if (record->albumartist)
  102. tag2_5->put_DiscArtist(record->albumartist);
  103. if (record->composer)
  104. tag2_5->put_Composer(record->composer);
  105. if (record->length > 0)
  106. tag2_5->put_LengthMS(_itow(record->length*1000, itemp, 10));
  107. if (record->bpm > 0)
  108. infotag->put_BeatsPerMinute(_itow(record->bpm, itemp, 10));
  109. /*
  110. if (GetFileInfo(filename, L"conductor", meta, 512) && meta[0])
  111. tag2_5->put_Conductor(meta);
  112. */
  113. AGAVE_API_MLDB->FreeRecord(record);
  114. }
  115. if (info) info->put_Tag(infotag);
  116. return S_OK;
  117. }
  118. struct Blah
  119. {
  120. IDispatch *callback;
  121. CComBSTR filename, tagID, artist;
  122. };
  123. static VOID CALLBACK InvokeAPC(ULONG_PTR param)
  124. {
  125. Blah *blah = (Blah *)param;
  126. VARIANT arguments[2];
  127. VariantInit(&arguments[0]);
  128. arguments[0].vt = VT_BSTR;
  129. arguments[0].bstrVal = blah->tagID;
  130. VariantInit(&arguments[1]);
  131. arguments[1].vt = VT_BSTR;
  132. arguments[1].bstrVal = blah->filename;
  133. DISPPARAMS params;
  134. params.cArgs = 2;
  135. params.cNamedArgs = 0;
  136. params.rgdispidNamedArgs = 0;
  137. params.rgvarg = arguments;
  138. unsigned int ret;
  139. if (!ieDisableSEH)
  140. {
  141. ieDisableSEH = AGAVE_API_CONFIG->GetItem(developerConfigGroupGUID, L"no_ieseh");
  142. }
  143. OLECHAR *setID = L"SetID", *setArtist = L"SetArtist", *onFinish=L"OnFinish";
  144. DISPID dispid;
  145. if (ieDisableSEH->GetBool() == false)
  146. {
  147. try
  148. {
  149. if (SUCCEEDED(blah->callback->GetIDsOfNames(IID_NULL, &setID, 1, LOCALE_SYSTEM_DEFAULT, &dispid)))
  150. blah->callback->Invoke(dispid, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
  151. else
  152. blah->callback->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
  153. arguments[0].bstrVal = blah->artist;
  154. if (SUCCEEDED(blah->callback->GetIDsOfNames(IID_NULL, &setArtist, 1, LOCALE_SYSTEM_DEFAULT, &dispid)))
  155. blah->callback->Invoke(dispid, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
  156. arguments[0].bstrVal = blah->filename;
  157. params.cArgs=1;
  158. if (SUCCEEDED(blah->callback->GetIDsOfNames(IID_NULL, &onFinish, 1, LOCALE_SYSTEM_DEFAULT, &dispid)))
  159. blah->callback->Invoke(dispid, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
  160. }
  161. catch (...)
  162. {
  163. }
  164. }
  165. else
  166. {
  167. if (SUCCEEDED(blah->callback->GetIDsOfNames(IID_NULL, &setID, 1, LOCALE_SYSTEM_DEFAULT, &dispid)))
  168. blah->callback->Invoke(dispid, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
  169. else
  170. blah->callback->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
  171. arguments[0].bstrVal = blah->artist;
  172. if (SUCCEEDED(blah->callback->GetIDsOfNames(IID_NULL, &setArtist, 1, LOCALE_SYSTEM_DEFAULT, &dispid)))
  173. blah->callback->Invoke(dispid, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
  174. arguments[0].bstrVal = blah->filename;
  175. params.cArgs=1;
  176. if (SUCCEEDED(blah->callback->GetIDsOfNames(IID_NULL, &onFinish, 1, LOCALE_SYSTEM_DEFAULT, &dispid)))
  177. blah->callback->Invoke(dispid, GUID_NULL, 0, DISPATCH_METHOD, &params, 0, 0, &ret);
  178. }
  179. delete blah;
  180. }
  181. class MyEventHandler : public _ICDDBMusicIDManagerEvents
  182. {
  183. public:
  184. MyEventHandler(BSTR _filename, IDispatch *_callback, HANDLE _handle) : callback(_callback), threadHandle(_handle)
  185. {
  186. filename = SysAllocString(_filename);
  187. refCount = 1;
  188. TestAddRef(callback);
  189. }
  190. BSTR filename;
  191. ICDDBMusicIDManager3 *musicID;
  192. HANDLE threadHandle;
  193. IDispatch *callback;
  194. ULONG STDMETHODCALLTYPE AddRef(void)
  195. {
  196. return InterlockedIncrement(&refCount);
  197. }
  198. ULONG STDMETHODCALLTYPE Release(void)
  199. {
  200. LONG lRef = InterlockedDecrement(&refCount);
  201. if (lRef == 0)
  202. delete this;
  203. return lRef;
  204. }
  205. private:
  206. ~MyEventHandler()
  207. {
  208. SysFreeString(filename);
  209. CloseHandle(threadHandle);
  210. TestRelease(callback);
  211. }
  212. LONG refCount;
  213. STDMETHODIMP STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppvObject)
  214. {
  215. if (!ppvObject)
  216. return E_POINTER;
  217. else if (IsEqualIID(riid, __uuidof(_ICDDBMusicIDManagerEvents)))
  218. *ppvObject = (_ICDDBMusicIDManagerEvents *)this;
  219. else if (IsEqualIID(riid, IID_IDispatch))
  220. *ppvObject = (IDispatch *)this;
  221. else if (IsEqualIID(riid, IID_IUnknown))
  222. *ppvObject = this;
  223. else
  224. {
  225. *ppvObject = NULL;
  226. return E_NOINTERFACE;
  227. }
  228. AddRef();
  229. return S_OK;
  230. }
  231. HRESULT STDMETHODCALLTYPE Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
  232. {
  233. switch (dispid)
  234. {
  235. case 1: // OnTrackIDStatusUpdate, params: CddbMusicIDStatus Status, BSTR filename, long* Abort
  236. break;
  237. case 2: // OnAlbumIDStatusUpdate, params: CddbMusicIDStatus Status, BSTR filename, long current_file, long total_files, long* Abort
  238. {
  239. //long *abort = pdispparams->rgvarg[0].plVal;
  240. //long total_files = pdispparams->rgvarg[1].lVal;
  241. //long current_file= pdispparams->rgvarg[2].lVal;
  242. CddbMusicIDStatus status = (CddbMusicIDStatus)pdispparams->rgvarg[4].lVal;
  243. BSTR filename = pdispparams->rgvarg[3].bstrVal;
  244. }
  245. break;
  246. case 3: // OnTrackIDComplete, params: LONG match_code, ICddbFileInfo* pInfoIn, ICddbFileInfoList* pListOut
  247. {
  248. IDispatch *disp1 =pdispparams->rgvarg[0].pdispVal;
  249. IDispatch *disp2 =pdispparams->rgvarg[1].pdispVal;
  250. //long match_code = pdispparams->rgvarg[2].lVal;
  251. ICddbFileInfoPtr pInfoIn;
  252. ICddbFileInfoListPtr matchList;
  253. disp1->QueryInterface(&matchList);
  254. disp2->QueryInterface(&pInfoIn);
  255. }
  256. break;
  257. case 4: // OnAlbumIDComplete, params: LONG match_code, ICddbFileInfoList* pListIn, ICddbFileInfoLists* pListsOut
  258. {
  259. IDispatch *disp1 =pdispparams->rgvarg[0].pdispVal;
  260. IDispatch *disp2 =pdispparams->rgvarg[1].pdispVal;
  261. //long match_code = pdispparams->rgvarg[2].lVal;
  262. ICddbFileInfoListPtr pListIn;
  263. ICddbFileInfoListsPtr pListsOut;
  264. disp1->QueryInterface(&pListsOut);
  265. disp2->QueryInterface(&pListIn);
  266. }
  267. break;
  268. case 10: // OnGetFingerprintInfo
  269. {
  270. long *abort = pdispparams->rgvarg[0].plVal;
  271. IDispatch *disp = pdispparams->rgvarg[1].pdispVal;
  272. BSTR filename = pdispparams->rgvarg[2].bstrVal;
  273. ICddbFileInfo *info;
  274. disp->QueryInterface(&info);
  275. return AGAVE_API_GRACENOTE->CreateFingerprint(musicID, AGAVE_API_DECODE, info, filename, abort);
  276. }
  277. break;
  278. case 11: // OnGetTagInfo
  279. {
  280. //long *Abort = pdispparams->rgvarg[0].plVal;
  281. IDispatch *disp = pdispparams->rgvarg[1].pdispVal;
  282. BSTR filename = pdispparams->rgvarg[2].bstrVal;
  283. ICddbFileInfo *info;
  284. disp->QueryInterface(&info);
  285. return FillTag(info, filename);
  286. }
  287. break;
  288. }
  289. return DISP_E_MEMBERNOTFOUND;
  290. }
  291. HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
  292. {
  293. *rgdispid = DISPID_UNKNOWN;
  294. return DISP_E_UNKNOWNNAME;
  295. }
  296. HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
  297. {
  298. return E_NOTIMPL;
  299. }
  300. HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int FAR * pctinfo)
  301. {
  302. return E_NOTIMPL;
  303. }
  304. };
  305. static VOID CALLBACK ReleaseAPC(ULONG_PTR param)
  306. {
  307. MyEventHandler *handler = (MyEventHandler *)param;
  308. handler->Release();
  309. }
  310. enum
  311. {
  312. DISPATCH_MUSICID_GETID = 777,
  313. };
  314. static std::vector<MyEventHandler*> tracks;
  315. static HANDLE musicid_killswitch=0, musicid_trigger=0;
  316. static ThreadID *musicIdThread=0;
  317. class MusicIDContext
  318. {
  319. public:
  320. MusicIDContext()
  321. {
  322. musicID=0;
  323. com_initted=false;
  324. }
  325. bool Init();
  326. void Tick();
  327. void Quit();
  328. ICDDBMusicIDManager3 *musicID;
  329. bool com_initted;
  330. };
  331. static MusicIDContext context;
  332. bool MusicIDContext::Init()
  333. {
  334. if (SUCCEEDED(CoInitialize(0)))
  335. com_initted=true;
  336. musicID=AGAVE_API_GRACENOTE->GetMusicID();
  337. return !!musicID;
  338. }
  339. void MusicIDContext::Tick()
  340. {
  341. musicIDGuard.Lock();
  342. if (tracks.empty())
  343. {
  344. musicIDGuard.Unlock();
  345. return;
  346. }
  347. MyEventHandler *track = tracks.front();
  348. tracks.pop_front();
  349. musicIDGuard.Unlock();
  350. if (!musicID)
  351. {
  352. Blah *blah = new Blah;
  353. blah->filename = SysAllocString(track->filename);
  354. blah->tagID = L"";
  355. blah->artist = L"";
  356. blah->callback=track->callback;
  357. QueueUserAPC(InvokeAPC, track->threadHandle, (ULONG_PTR)blah);
  358. QueueUserAPC(ReleaseAPC, track->threadHandle, (ULONG_PTR)track);
  359. return;
  360. }
  361. track->musicID = musicID;
  362. IConnectionPoint *icp = GetConnectionPoint(musicID, DIID__ICDDBMusicIDManagerEvents);
  363. DWORD m_dwCookie=0;
  364. if (icp)
  365. {
  366. icp->Advise(static_cast<IDispatch *>(track), &m_dwCookie);
  367. //icp->Release();
  368. }
  369. ICddbFileInfoPtr info;
  370. info.CreateInstance(CLSID_CddbFileInfo);
  371. if (info == 0)
  372. {
  373. QueueUserAPC(ReleaseAPC, track->threadHandle, (ULONG_PTR)track);
  374. return ;
  375. }
  376. info->put_Filename(track->filename);
  377. ICddbFileInfoListPtr matchList;
  378. long match_code=666;
  379. musicID->TrackID(info, MUSICID_RETURN_SINGLE|MUSICID_GET_TAG_FROM_APP|MUSICID_GET_FP_FROM_APP|MUSICID_PREFER_WF_MATCHES, &match_code, &matchList);
  380. if (matchList)
  381. {
  382. long matchcount;
  383. matchList->get_Count(&matchcount);
  384. assert(matchcount==1);
  385. for (int j = 1;j <= matchcount;j++)
  386. {
  387. ICddbFileInfoPtr match;
  388. matchList->GetFileInfo(j, &match);
  389. Blah *blah = new Blah;
  390. match->get_Filename(&blah->filename);
  391. ICddbFileTagPtr tag;
  392. match->get_Tag(&tag);
  393. tag->get_FileId(&blah->tagID);
  394. tag->get_LeadArtist(&blah->artist);
  395. blah->callback=track->callback;
  396. if (blah->tagID && AGAVE_API_MLDB)
  397. AGAVE_API_MLDB->SetField(blah->filename, "GracenoteFileID", blah->tagID);
  398. QueueUserAPC(InvokeAPC, track->threadHandle, (ULONG_PTR)blah);
  399. if (AGAVE_API_MLDB)
  400. AGAVE_API_MLDB->Sync();
  401. //TODO: optionally write metadata to file permanently
  402. }
  403. }
  404. if (icp)
  405. {
  406. icp->Unadvise(m_dwCookie);
  407. }
  408. QueueUserAPC(ReleaseAPC, track->threadHandle, (ULONG_PTR)track);
  409. }
  410. void MusicIDContext::Quit()
  411. {
  412. if (musicID)
  413. {
  414. musicID->Shutdown();
  415. musicID->Release();
  416. musicID=0;
  417. }
  418. if (com_initted)
  419. {
  420. CoUninitialize();
  421. com_initted=false;
  422. }
  423. }
  424. static int MusicIDTickThreadPoolFunc(HANDLE handle, void *user_data, intptr_t id)
  425. {
  426. MusicIDContext *context = (MusicIDContext *)user_data;
  427. context->Tick();
  428. return 0;
  429. }
  430. static int MusicIDInitThreadPoolFunc(HANDLE handle, void *user_data, intptr_t id)
  431. {
  432. MusicIDContext *context = (MusicIDContext *)user_data;
  433. if (context->Init())
  434. {
  435. AGAVE_API_THREADPOOL->AddHandle(musicIdThread, musicid_trigger, MusicIDTickThreadPoolFunc, user_data, id, 0);
  436. }
  437. return 0;
  438. }
  439. static int MusicIDQuitThreadPoolFunc(HANDLE handle, void *user_data, intptr_t id)
  440. {
  441. MusicIDContext *context = (MusicIDContext *)user_data;
  442. AGAVE_API_THREADPOOL->RemoveHandle(musicIdThread, musicid_trigger);
  443. context->Quit();
  444. SetEvent(musicid_killswitch);
  445. return 0;
  446. }
  447. HRESULT MusicIDCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
  448. {
  449. bool unknowns = false;
  450. for (unsigned int i = 0;i != cNames;i++)
  451. {
  452. if (wcscmp(rgszNames[i], L"GetID") == 0)
  453. rgdispid[i] = DISPATCH_MUSICID_GETID;
  454. else
  455. {
  456. rgdispid[i] = DISPID_UNKNOWN;
  457. unknowns = true;
  458. }
  459. }
  460. if (unknowns)
  461. return DISP_E_UNKNOWNNAME;
  462. else
  463. return S_OK;
  464. }
  465. HRESULT MusicIDCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
  466. {
  467. return E_NOTIMPL;
  468. }
  469. HRESULT MusicIDCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
  470. {
  471. return E_NOTIMPL;
  472. }
  473. HRESULT MusicIDCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
  474. {
  475. if (dispid == DISPATCH_MUSICID_GETID)
  476. {
  477. if (pdispparams->cArgs != 2)
  478. return DISP_E_BADPARAMCOUNT;
  479. if (pdispparams->rgvarg[0].vt != VT_DISPATCH)
  480. return DISP_E_TYPEMISMATCH;
  481. if (pdispparams->rgvarg[1].vt != VT_BSTR)
  482. return DISP_E_TYPEMISMATCH;
  483. if (!AGAVE_API_GRACENOTE)
  484. return E_FAIL;
  485. if (!musicIdThread)
  486. {
  487. musicIDGuard.Lock();
  488. if (!musicIdThread)
  489. {
  490. musicIdThread = AGAVE_API_THREADPOOL->ReserveThread(api_threadpool::FLAG_REQUIRE_COM_STA);
  491. musicid_trigger = CreateSemaphore(0, 0, 65536, 0);
  492. AGAVE_API_THREADPOOL->RunFunction(musicIdThread, MusicIDInitThreadPoolFunc, &context, 0, 0);
  493. }
  494. musicIDGuard.Unlock();
  495. }
  496. MyEventHandler *event = new MyEventHandler(pdispparams->rgvarg[1].bstrVal, pdispparams->rgvarg[0].pdispVal, DuplicateCurrentThread());
  497. musicIDGuard.Lock();
  498. tracks.push_back(event);
  499. musicIDGuard.Unlock();
  500. ReleaseSemaphore(musicid_trigger, 1, 0);
  501. return S_OK;
  502. }
  503. return DISP_E_MEMBERNOTFOUND;
  504. }
  505. STDMETHODIMP MusicIDCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
  506. {
  507. if (!ppvObject)
  508. return E_POINTER;
  509. else if (IsEqualIID(riid, IID_IDispatch))
  510. *ppvObject = (IDispatch *)this;
  511. else if (IsEqualIID(riid, IID_IUnknown))
  512. *ppvObject = this;
  513. else
  514. {
  515. *ppvObject = NULL;
  516. return E_NOINTERFACE;
  517. }
  518. AddRef();
  519. return S_OK;
  520. }
  521. ULONG MusicIDCOM::AddRef(void)
  522. {
  523. // return ++m_cRefs;
  524. return 0;
  525. }
  526. ULONG MusicIDCOM::Release(void)
  527. { /*
  528. if (--m_cRefs)
  529. return m_cRefs;
  530. delete this;
  531. return 0;*/
  532. return 0;
  533. }
  534. void MusicIDCOM::Quit()
  535. {
  536. if (musicIdThread)
  537. {
  538. musicid_killswitch = CreateEvent(NULL, FALSE, FALSE, NULL);
  539. AGAVE_API_THREADPOOL->RunFunction(musicIdThread, MusicIDQuitThreadPoolFunc, &context, 0, 0);
  540. if (NULL != musicid_killswitch)
  541. {
  542. WaitForSingleObject(musicid_killswitch, INFINITE);
  543. CloseHandle(musicid_killswitch);
  544. }
  545. CloseHandle(musicid_trigger);
  546. AGAVE_API_THREADPOOL->ReleaseThread(musicIdThread);
  547. }
  548. }
  549. #endif