diff options
Diffstat (limited to 'Src/Plugins/Input/in_cdda/CDDB.Cpp')
-rw-r--r-- | Src/Plugins/Input/in_cdda/CDDB.Cpp | 1709 |
1 files changed, 1709 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_cdda/CDDB.Cpp b/Src/Plugins/Input/in_cdda/CDDB.Cpp new file mode 100644 index 00000000..626cc329 --- /dev/null +++ b/Src/Plugins/Input/in_cdda/CDDB.Cpp @@ -0,0 +1,1709 @@ +#include "main.h" +#include "api__in_cdda.h" + +#include "cddbinterface.h" +#include "cddb.h" +#include "../nu/AutoWide.h" +#include "../nu/AutoChar.h" +#include "../winamp/wa_ipc.h" +#include "../nu/ns_wc.h" +#include ".\cddbevnt.h" +#include ".\cddbui.h" +#include ".\grabwnd.h" +#include <api/application/api_application.h> +#include <atlbase.h> +#include "../nde/ndestring.h" +#include "../Winamp/buildtype.h" +#include <commctrl.h> +#include <strsafe.h> + +// {C0A565DC-0CFE-405a-A27C-468B0C8A3A5C} +static const GUID internetConfigGroupGUID = + { 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c } }; + +TRACKINFO::~TRACKINFO() +{ + Reset(); +} + +void TRACKINFO::Reset() +{ +ndestring_release(artist); + artist=0; + ndestring_release(title); + title=0; + ndestring_release(tagID); + tagID=0; + ndestring_release(composer); + composer=0; + ndestring_release(conductor); + conductor=0; + ndestring_release(extData); + extData=0; + ndestring_release(remixing); + remixing=0; + ndestring_release(isrc); + isrc=0; +} + +TRACKINFO::TRACKINFO(const TRACKINFO ©) +{ + operator =(copy); +} + +TRACKINFO &TRACKINFO::operator =(const TRACKINFO ©) +{ + ndestring_retain(artist=copy.artist); + ndestring_retain(title=copy.title); + ndestring_retain(tagID=copy.tagID); + ndestring_retain(composer=copy.composer); + ndestring_retain(conductor=copy.conductor); + ndestring_retain(extData=copy.extData); + ndestring_retain(remixing=copy.remixing); + ndestring_retain(isrc=copy.isrc); + return *this; +} + +void DINFO::Reset() +{ + ndestring_release(title); + title=0; + ndestring_release(artist); + artist=0; + ndestring_release(tuid); + tuid=0; + ndestring_release(year); + year=0; + ndestring_release(genre); + genre=0; + ndestring_release(label); + label=0; + ndestring_release(notes); + notes=0; + ndestring_release(conductor); + conductor=0; + ndestring_release(composer); + composer=0; + ndestring_release(remixing); + remixing=0; + discnum=0; + numdiscs=0; +} + +DINFO::~DINFO() +{ + Reset(); +} + +DINFO::DINFO(const DINFO ©) +{ + operator =(copy); +} + +DINFO &DINFO::operator =(const DINFO ©) +{ + ndestring_retain(title=copy.title); + ndestring_retain(artist=copy.artist); + ndestring_retain(tuid=copy.tuid); + ndestring_retain(year=copy.year); + ndestring_retain(genre=copy.genre); + ndestring_retain(label=copy.label); + ndestring_retain(notes=copy.notes); + compilation=copy.compilation; + discnum=copy.discnum; + numdiscs=copy.numdiscs; + ntracks=copy.ntracks; + ndestring_retain(conductor=copy.conductor); + ndestring_retain(composer=copy.composer); + ndestring_retain(remixing=copy.remixing); + for (int i=0;i<sizeof(tracks)/sizeof(*tracks);i++) + tracks[i]=copy.tracks[i]; + + CDDBID=copy.CDDBID; + memcpy(pnFrames, copy.pnFrames, sizeof(pnFrames)); + nDiscLength=copy.nDiscLength; + + populated=copy.populated; + return *this; +} + + +#define TM_INVOKERESULTS (WM_APP + 222) +#define TM_UNINITTHREAD (WM_APP + 2) + +#define CENTER_PARENT (-32000) +#define CENTER_LEFT 0x0001 +#define CENTER_TOP 0x0002 + +#define WASABI_WND_CLASSW L"BaseWindow_RootWnd" + +#define INVARIANT_LCID MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) + +typedef struct _MEDIALOOKUP +{ + HRESULT result; + HWND hwndInfo; + CDDB_CB callback; + ULONG_PTR user; + UINT flags; + BSTR bstrTOC; + DWORD threadId; +} MEDIALOOKUP; + +typedef struct _THREADDATA +{ + LONG ref; + HHOOK hhook; + BOOL uninitCom; +} THREADDATA; + +CRITICAL_SECTION lockThread; + +typedef struct _INVOKEDATA +{ + MEDIALOOKUP lookup; + ICddbDisc *pDisc; + HANDLE evntDone; + DWORD *pdwAutoCloseDelay; +} INVOKEDATA; + +static DWORD tlsSlot = TLS_OUT_OF_INDEXES; +#ifndef IGNORE_API_GRACENOTE +ICDDBControl *pCDDBControl=0; +static CDBBEventManager eventMngr; +#endif +static MEDIALOOKUP g_lookup = {0, 0, }; +static HANDLE evntBusy = NULL; +static LONG evntBusyRef = 0; +static HWND hwndProgressListener = NULL; +static ICddbDisc *pSubmitDisc = NULL; +static POINT g_lastcddbpos = { CENTER_PARENT, CENTER_PARENT}; // center + + +static HRESULT SetupCDDB(BOOL resetError); +static void CALLBACK Cddb_OnCommandCompleted(LONG lCommandCode, HRESULT hCommandResult, VARIANT *pCommandData, UINT_PTR user); +static void CALLBACK Cddb_OnCommandProgress(LONG lCommandCode, LONG lProgressCode, LONG lBytesDone, LONG lBytesTotal, UINT_PTR user); +#ifndef IGNORE_API_GRACENOTE +static void Cddb_OnMediaLookupCompleted(HRESULT hr, CDDBMatchCode matchCode, MEDIALOOKUP *pLookup); +static void Cddb_OnGetFullDiscInfoCompleted(HRESULT hr, ICddbDisc *pDisc, MEDIALOOKUP *pLookup); +static void Cddb_OnSubmitDiscCompleted(HRESULT result, MEDIALOOKUP *pLookup); + +static HRESULT Cddb_DoFuzzyMatchDlg(HWND hwndCaller, UINT flags, ICddbDiscs *pDiscs, LONG *plVal); +static HRESULT Cddb_DoSubmitNewDlg(HWND hwndCaller, LPCWSTR pszTOC, UINT flags, ICddbDisc **ppDisc); + +#define CLEARLOOKUP() SecureZeroMemory(&g_lookup, sizeof(MEDIALOOKUP)) +#define IS_BUSY(__timeout) (evntBusy && (WAIT_OBJECT_0 == WaitForSingleObject(evntBusy, (__timeout)))) +#define SET_BUSY(__enable) ((__enable) ? (SetEvent(evntBusy)) : ResetEvent(evntBusy)) + +void ShutDownCDDB() +{ + if (pCDDBControl) + { + eventMngr.Unadvise(pCDDBControl); + pCDDBControl->Release(); + pCDDBControl=0; + } +} +#endif + +static HWND GetAdaptedParent(HWND hwndParent) +{ + if (!hwndParent || !IsWindow(hwndParent)) hwndParent = line.hMainWindow; + if (!hwndParent || !IsWindow(hwndParent)) hwndParent = GetDesktopWindow(); + if (hwndParent == line.hMainWindow) + { + hwndParent = (HWND)SendMessageW(line.hMainWindow, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT); + if (!IsWindow(hwndParent)) hwndParent = line.hMainWindow; + } + return hwndParent; +} + +static BOOL CalculatePopUpPos(RECT *prcParent, RECT *prcPopUp, UINT flags) +{ + LONG x, y; + MONITORINFO mi; + if (!prcPopUp) return FALSE; + + if (prcParent) + { + x = prcParent->left; + y = prcParent->top; + + OffsetRect(prcPopUp, -prcPopUp->left, -prcPopUp->top); + OffsetRect(prcParent, -prcParent->left, -prcParent->top); + if (CENTER_LEFT & flags) x += (prcParent->right - prcPopUp->right)/2; + if (CENTER_TOP & flags) y += (prcParent->bottom - prcPopUp->bottom )/2; + + SetRect(prcPopUp, x, y, x + prcPopUp->right, y + prcPopUp->bottom); + } + mi.cbSize = sizeof(MONITORINFO); + HMONITOR hMonitor = MonitorFromRect(prcPopUp, MONITOR_DEFAULTTONULL); + if (!hMonitor) + { + OffsetRect(prcPopUp, -prcPopUp->left, -prcPopUp->top); + hMonitor = MonitorFromRect(prcPopUp, MONITOR_DEFAULTTONEAREST); + + if(GetMonitorInfo(hMonitor, &mi)) + { + x = mi.rcWork.left + ((mi.rcWork.right - mi.rcWork.left) - prcPopUp->right)/2; + if(x < mi.rcWork.left) x = mi.rcWork.left; + y = mi.rcWork.top + ((mi.rcWork.bottom - mi.rcWork.top) - prcPopUp->bottom)/2; + if(y < mi.rcWork.top) y = mi.rcWork.top; + SetRect(prcPopUp, x, y, x + prcPopUp->right, y + prcPopUp->bottom); + } + } + else + { + if(GetMonitorInfo(hMonitor, &mi)) + { + if (prcPopUp->right > mi.rcWork.right) + { + OffsetRect(prcPopUp, mi.rcWork.right - prcPopUp->right, 0); + } + } + } + return TRUE; +} + +static BOOL SetPopUpPos(HWND hwnd, UINT flags) +{ + RECT rc, rw; + + if (!hwnd) return FALSE; + + HWND hwndParent = GetParent(hwnd); + hwndParent = GetAdaptedParent(hwndParent); + + if (GetClientRect(hwndParent, &rc) && GetWindowRect(hwnd, &rw)) + { + HWND hwndFound; + wchar_t szClass[2048] = {0}; + UINT flags = CENTER_LEFT; + + MapWindowPoints(hwndParent, HWND_DESKTOP, (POINT*)&rc, 2); + + if (hwndParent == line.hMainWindow || + (GetClassNameW(hwndParent, szClass, sizeof(szClass)/sizeof(wchar_t)) && + CSTR_EQUAL == CompareStringW(INVARIANT_LCID, 0, szClass, -1, WASABI_WND_CLASSW, -1) && + NULL != (hwndFound = FindWindowEx(NULL, hwndParent, WASABI_WND_CLASSW, NULL))) + && IsWindowVisible(hwndFound)) + { + OffsetRect(&rc, (rc.right - rc.left + 4), 0); + flags &= ~ CENTER_LEFT; + } + if (CalculatePopUpPos(&rc, &rw, flags)) + { + SetWindowPos(hwnd, HWND_TOP, rw.left, rw.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE); + } + } + return TRUE; +} + +static void Cddb_ProcessResult(MEDIALOOKUP *pLookup, ICddbDisc *pDisc, DWORD *pdwAutoCloseDelay) +{ + if (pLookup && pLookup->callback) pLookup->callback(pLookup->result, pDisc, pdwAutoCloseDelay, pLookup->user); +} + +static void CALLBACK Execute_ProcessResult(INVOKEDATA *pData) +{ + #ifndef IGNORE_API_GRACENOTE + INVOKEDATA data; + + if (!pData) return; + + CopyMemory(&data, &pData->lookup, sizeof(INVOKEDATA)); + if (data.pDisc) + data.pDisc->AddRef(); + + Cddb_ProcessResult(&data.lookup, data.pDisc, data.pdwAutoCloseDelay); + if (data.pDisc) + data.pDisc->Release(); + if (data.evntDone) + SetEvent(data.evntDone); + #endif +} + +static LRESULT CALLBACK HookMessageProc(int code, WPARAM wParam, LPARAM lParam) +{ + THREADDATA *pData; + + if (TLS_OUT_OF_INDEXES == tlsSlot) return 0; + pData = (THREADDATA*)TlsGetValue(tlsSlot); + if (!pData) return 0; + + if (code < 0) return CallNextHookEx(pData->hhook, code, wParam, lParam); + + if (NULL == ((MSG*)lParam)->hwnd) // thread message + { + switch(((MSG*)lParam)->message) + { + case TM_INVOKERESULTS: + Execute_ProcessResult((INVOKEDATA*)((MSG*)lParam)->lParam); + return TRUE; + case TM_UNINITTHREAD: + Cddb_UninitializeThread(); + return TRUE; + } + } + + return CallNextHookEx(pData->hhook, code, wParam, lParam); +} + +void Cddb_Initialize(void) +{ + InitializeCriticalSection(&lockThread); +} + +void Cddb_Uninitialize(void) +{ + DeleteCriticalSection(&lockThread); +} + +static HRESULT Cddb_IsThreadInitialized(void) +{ + THREADDATA *pData; + if (TLS_OUT_OF_INDEXES == tlsSlot) return E_OUTOFMEMORY; + pData = (THREADDATA*)TlsGetValue(tlsSlot); + return (pData) ? S_OK : S_FALSE; +} + +static HANDLE GetMainThreadHandle(void) +{ + HANDLE hThread = NULL; + api_application *pApp = NULL; + waServiceFactory *sf = NULL; + + if (!line.service) return NULL; + if (NULL == (sf = line.service->service_getServiceByGuid(applicationApiServiceGuid))) return NULL; + if (NULL == (pApp = (api_application*)sf->getInterface())) { return NULL; } + + hThread = pApp->main_getMainThreadHandle(); + sf->releaseInterface(pApp); + + return hThread; +} + +static HRESULT Cddb_InvokeProcessResult(MEDIALOOKUP *pLookup, ICddbDisc *pDisc, DWORD *pdwAutoCloseDelay) +{ + HRESULT hr = E_FAIL; + #ifndef IGNORE_API_GRACENOTE + INVOKEDATA data; + if (!pLookup) return E_INVALIDARG; + CopyMemory(&data.lookup, pLookup, sizeof(MEDIALOOKUP)); + data.pDisc = pDisc; + data.pdwAutoCloseDelay = pdwAutoCloseDelay; + if (NULL != pDisc) + pDisc->AddRef(); + + if (!data.lookup.threadId) data.lookup.threadId = GetWindowThreadProcessId(line.hMainWindow, NULL); + if (data.lookup.threadId != GetCurrentThreadId()) + { + data.evntDone = CreateEvent(NULL, FALSE, FALSE, NULL); + if (data.evntDone) + { + if (PostThreadMessage(data.lookup.threadId, TM_INVOKERESULTS, 0, (LPARAM)&data)) + { + MSG msg; + msg.message = NULL; + + for(;;) + { + DWORD status = MsgWaitForMultipleObjectsEx(1, &data.evntDone, + INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); + + if (status == WAIT_OBJECT_0+1) + { + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (WM_QUIT == msg.message) + { + break; + } + if (0 == CallMsgFilter(&msg, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + else if (status == WAIT_OBJECT_0) + { + break; + } + } + + if (WM_QUIT == msg.message) + PostQuitMessage((int)msg.wParam); + hr = S_OK; + } + CloseHandle(data.evntDone); + } + } + else + { + Cddb_ProcessResult(pLookup, pDisc, pdwAutoCloseDelay); + hr = S_OK; + } + + if (NULL != pDisc) + pDisc->Release(); + #endif + return hr; +} + +#ifndef IGNORE_API_GRACENOTE +bool GetRole(ICddbTrack *track, BSTR roleId, BSTR *str) +{ + if (!roleId || !*roleId) + return false; + + if (!track) + return false; + + ICddbCreditsPtr credits; + track->get_Credits(&credits); + if (credits) + { + long creditCount; + credits->get_Count(&creditCount); + for (long c = 0;c < creditCount;c++) + { + ICddbCreditPtr credit; + credits->GetCredit(c + 1, &credit); + if (credit) + { + BSTR thisRole; + credit->get_Id(&thisRole); + if (!wcscmp(thisRole, roleId)) + { + credit->get_Name(str); + return true; + } + } + } + } + return false; +} + +bool GetRole(ICddbDisc *track, BSTR roleId, BSTR *str) +{ + if (!roleId || !*roleId) + return false; + + if (!track) + return false; + + ICddbCreditsPtr credits; + track->get_Credits(&credits); + if (credits) + { + long creditCount; + credits->get_Count(&creditCount); + for (long c = 0;c < creditCount;c++) + { + ICddbCreditPtr credit; + credits->GetCredit(c + 1, &credit); + if (credit) + { + BSTR thisRole; + credit->get_Id(&thisRole); + if (!wcscmp(thisRole, roleId)) + { + credit->get_Name(str); + return true; + } + } + } + } + return false; +} +#endif + +HRESULT Cddb_InitializeThread(void) +{ + HRESULT hr = S_OK; + EnterCriticalSection(&lockThread); + + if (!evntBusy) + { + evntBusyRef = 0; + evntBusy = CreateEvent(NULL, TRUE, FALSE, NULL); + if (NULL == evntBusy) + hr = E_UNEXPECTED; + } + + if (SUCCEEDED(hr)) + { + evntBusyRef++; + + if (TLS_OUT_OF_INDEXES == tlsSlot && + TLS_OUT_OF_INDEXES == (tlsSlot = TlsAlloc())) + hr = E_OUTOFMEMORY; + + if (SUCCEEDED(hr)) + { + THREADDATA *pData = (THREADDATA*)TlsGetValue(tlsSlot); + if (pData) + { + pData->ref++; + } + else + { + pData = (THREADDATA*)calloc(1, sizeof(THREADDATA)); + if (!pData) + { + hr = E_OUTOFMEMORY; + } + if (SUCCEEDED(hr)) + { + pData->hhook = SetWindowsHookExW(WH_MSGFILTER, HookMessageProc, NULL, GetCurrentThreadId()); + if (!pData->hhook || !TlsSetValue(tlsSlot, pData)) + { + if (pData->hhook) UnhookWindowsHookEx(pData->hhook); + free(pData); + pData = NULL; + hr = E_FAIL; + } + else + { + pData->ref = 1; + pData->uninitCom = (S_OK == CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); + hr = S_OK; + } + } + } + } + } + LeaveCriticalSection(&lockThread); + return hr; +} + +HRESULT Cddb_UninitializeThread(void) +{ + EnterCriticalSection(&lockThread); + + if (TLS_OUT_OF_INDEXES != tlsSlot) + { + THREADDATA *pData = (THREADDATA*)TlsGetValue(tlsSlot); + if (NULL != pData && + pData->ref && 0 == --pData->ref) + { + TlsSetValue(tlsSlot, NULL); + if (pData->hhook) + UnhookWindowsHookEx(pData->hhook); + + if (pData->uninitCom) + CoUninitialize(); + + free(pData); + } + } + + if (evntBusyRef && 0 == --evntBusyRef) + { + CloseHandle(evntBusy); + evntBusy = NULL; + } + + LeaveCriticalSection(&lockThread); + return S_OK; +} + +LPCWSTR Cddb_CalculateTOC(DINFO *pDisc, LPWSTR pszTOC, size_t cchTOC) +{ + LPWSTR p; + if (!pszTOC || !pDisc || !cchTOC) return NULL; + pszTOC[0] = 0x00; + p = pszTOC; + for (int x = 0; x < pDisc->ntracks + 1; x++) + { + if (S_OK != StringCchPrintfExW(p, cchTOC, &p, &cchTOC, + STRSAFE_NULL_ON_FAILURE, L"%lu ", pDisc->pnFrames[x])) return NULL; + } + if (p != pszTOC) *(p - 1) = 0x00; + return pszTOC; +} + +// 2 author (???) +// 3 composer +// 6 lyricist +// 7 publisher (how is this different from label?) +// 9 songwriter (music & lyrics) +// 10 conductor/arranger +// 11 Arranger +// 12 Conductor +// 13 Director +// 72 Engineer +// 74 Mastering +// 75 Mastering Location +// 76 Mixing +// 77 Mixing Location +// 78 Producer +// 79 Programming (???) +// 80 Recording Location +// 147 remixer +#ifndef IGNORE_API_GRACENOTE +void GetDiscInfo(ICddbDiscPtr pDisc, DINFO *ps) +{ + CComBSTR str, disc_artist, disc_composer, disc_conductor, disc_remixing; + BSTR composerRole=L"3", conductorRole=L"12", remixingRole=L"147"; + + /* + for (int i=0;i<100;i++) + { + wchar_t id[256] = {0}; + _itow(i, id, 10); + ICddbRolePtr role; + pCDDBControl->GetRoleInfo(id, &role); + if (role) + { + BSTR name, description; + role->get_Name(&name); + role->get_Description(&description); + wchar_t str[4096] = {0}; + wsprintf(str, L"ID: %s\r\nName: %s\r\nDescription: %s\r\n", id, name, description); + MessageBoxW(NULL, str, L"CDDB Role", MB_OK); + } + } + */ + + ps->Reset(); + if (pDisc == NULL) // yikes! + return; + ICddbDisc2Ptr pDisc2; + pDisc->QueryInterface(&pDisc2); + + ICddbDisc2_5Ptr pDisc2_5; + pDisc->QueryInterface(&pDisc2_5); + + if (GetRole(pDisc, conductorRole, &disc_conductor) && disc_conductor && disc_conductor.m_str[0]) + ps->conductor = ndestring_wcsdup(disc_conductor.m_str); + + if (GetRole(pDisc, composerRole, &disc_composer) && disc_composer && disc_composer.m_str[0]) + ps->composer = ndestring_wcsdup(disc_composer.m_str); + + if (GetRole(pDisc, remixingRole, &disc_remixing) && disc_remixing && disc_remixing.m_str[0]) + ps->remixing = ndestring_wcsdup(disc_remixing.m_str); + + if (SUCCEEDED(pDisc->get_Artist(&disc_artist)) && disc_artist && disc_artist.m_str[0]) + ps->artist = ndestring_wcsdup(disc_artist.m_str); + + if (SUCCEEDED(pDisc->get_Year(&str)) && str && str.m_str[0]) + ps->year = ndestring_wcsdup(str.m_str); + + if (pDisc2_5 == NULL + || (FAILED(pDisc2_5->get_V2GenreStringPrimaryByLevel(3, &str)) + && FAILED(pDisc2_5->get_V2GenreStringPrimaryByLevel(2, &str)) + && FAILED(pDisc2_5->get_V2GenreStringPrimaryByLevel(1, &str)) + && FAILED(pDisc2_5->get_V2GenreStringPrimary(&str))) + ) + { + pDisc->get_GenreId(&str); + ICddbGenre *poop = 0; + if (SUCCEEDED(pCDDBControl->GetGenreInfo(str, &poop)) && poop) + { + poop->get_Name(&str); + poop->Release(); + } + else + str.Empty(); + } + if (str && str.m_str[0]) + ps->genre = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(pDisc->get_Title(&str)) && str && str.m_str[0]) + ps->title = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(pDisc->get_TitleUId(&str)) && str && str.m_str[0]) + ps->tuid = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(pDisc->get_Label(&str)) && str && str.m_str[0]) + ps->label = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(pDisc->get_Notes(&str)) && str && str.m_str[0]) + ps->notes = ndestring_wcsdup(str.m_str); + + long val; + if (SUCCEEDED(pDisc->get_Compilation(&val))) + ps->compilation = !!val; + + if (SUCCEEDED(pDisc->get_TotalInSet(&str)) && str && str.m_str[0]) + ps->numdiscs = _wtoi(str.m_str); + + if (SUCCEEDED(pDisc->get_NumberInSet(&str)) && str && str.m_str[0]) + ps->discnum = _wtoi(str.m_str); + + for (int x = 0; x < ps->ntracks; x ++) + { + TRACKINFO &trackInfo = ps->tracks[x]; + ICddbTrack *t; + ICddbTrack2_5Ptr track2_5; + pDisc->GetTrack(x + 1, &t); + if (!t) break; + + t->QueryInterface(&track2_5); + + if (SUCCEEDED(t->get_Artist(&str)) && str && str.m_str[0] && (!disc_artist || !disc_artist.m_str[0] || wcscmp(str.m_str, disc_artist.m_str))) + trackInfo.artist = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(t->get_Title(&str)) && str && str.m_str[0]) + trackInfo.title = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(t->get_ISRC(&str)) && str && str.m_str[0]) + trackInfo.isrc = ndestring_wcsdup(str.m_str); + + if (SUCCEEDED(pCDDBControl->GetDiscTagId(pDisc, x + 1, &str)) && str && str.m_str[0]) + trackInfo.tagID = ndestring_wcsdup(str.m_str); + + if (GetRole(t, conductorRole, &str) && str && str.m_str[0] && (!disc_conductor || !disc_conductor.m_str[0] || wcscmp(str.m_str, disc_conductor.m_str))) + trackInfo.conductor = ndestring_wcsdup(str.m_str); + + if (GetRole(t, composerRole, &str) && str && str.m_str[0] && (!disc_composer || !disc_composer.m_str[0] || wcscmp(str.m_str, disc_composer.m_str))) + trackInfo.composer = ndestring_wcsdup(str.m_str); + + if (GetRole(t, remixingRole, &str) && str && str.m_str[0] && (!disc_remixing || !disc_remixing.m_str[0] || wcscmp(str.m_str, disc_remixing.m_str))) + trackInfo.remixing = ndestring_wcsdup(str.m_str); + + if (track2_5 != NULL && (SUCCEEDED(track2_5->get_ExtDataSerialized(&str)) && str && str.m_str[0]) // try track first + || (pDisc2_5 != NULL && SUCCEEDED(pDisc2_5->get_ExtDataSerialized(&str)) && str && str.m_str[0])) // then disc + trackInfo.extData = ndestring_wcsdup(str.m_str); + + t->Release(); + } + + ps->populated = true; +} +#endif + +HRESULT Cddb_GetIUIOptions(void **ppUIOptions) +{ + HRESULT hr; + + if (!ppUIOptions) return E_INVALIDARG; + *ppUIOptions = NULL; + + hr = SetupCDDB(FALSE); + if (SUCCEEDED(hr)) + { + #ifndef IGNORE_API_GRACENOTE + hr = CoCreateInstance(CLSID_CddbUIOptions, NULL, + CLSCTX_INPROC_SERVER, IID_ICddbUIOptions, ppUIOptions); + #endif + } + return hr; +} + +HRESULT Cddb_GetIControl(void **ppControl) +{ + HRESULT hr; + + if (!ppControl) return E_INVALIDARG; + *ppControl = NULL; + + hr = SetupCDDB(FALSE); + if(SUCCEEDED(hr)) + { + #ifndef IGNORE_API_GRACENOTE + pCDDBControl->AddRef(); + *ppControl = pCDDBControl; + #endif + } + return hr; +} + +HRESULT Cddb_GetICacheManger(void **ppCache) +{ + HRESULT hr; + + if (!ppCache) return E_INVALIDARG; + *ppCache = NULL; + + hr = SetupCDDB(FALSE); + if (SUCCEEDED(hr)) + { + #ifndef IGNORE_API_GRACENOTE + hr = CoCreateInstance(CLSID_CddbCacheManager, NULL, + CLSCTX_INPROC_SERVER, IID_ICddbCacheManager, ppCache); + #endif + } + return hr; +} + +static HRESULT SetupCDDB(BOOL resetError) +{ + static HRESULT result(S_FALSE); + + #ifndef IGNORE_API_GRACENOTE + if (S_FALSE == result || (FAILED(result) && resetError)) + { + if (AGAVE_API_GRACENOTE) + pCDDBControl = AGAVE_API_GRACENOTE->GetCDDB(); + result = (NULL == pCDDBControl) ? CDDBCTLNotInitialized : S_OK; + if (SUCCEEDED(result)) + { + HRESULT hr; + ICddbOptionsPtr pOptions; + hr = pCDDBControl->GetOptions(&pOptions); + if (SUCCEEDED(hr)) + { + LONG lVal; + BOOL bUpdate(FALSE); + hr = pOptions->get_AsyncCompletion(&lVal); + if (SUCCEEDED(hr) && !lVal) { pOptions->put_AsyncCompletion(1); bUpdate = TRUE; } + hr = pOptions->get_ProgressEvents(&lVal); + if (SUCCEEDED(hr) && !lVal) { pOptions->put_ProgressEvents(1); bUpdate = TRUE; } + +#if defined(BETA) || defined(INTERNAL) || defined(NIGHT) + pOptions->put_TestSubmitMode(TRUE); // BETA +#endif + + if (bUpdate) pCDDBControl->SetOptions(pOptions); + } + if (SUCCEEDED(eventMngr.Advise(pCDDBControl))) + { + eventMngr.RegisterCallback(CDDB_CB_CMDCOMPLETED, Cddb_OnCommandCompleted); + eventMngr.RegisterCallback(CDDB_CB_CMDPROGRESS, Cddb_OnCommandProgress); + } + + } + } + #endif + return result; +} + +#ifndef IGNORE_API_GRACENOTE +HRESULT Cddb_GetDiscFromCache(BSTR bstrTOC, ICddbDisc **ppDisc) +{ + HRESULT hr; + ICddbCacheManager *pCache; + + if (!ppDisc) return E_INVALIDARG; + *ppDisc = NULL; + + if (!bstrTOC) return CDDB_E_BADTOC; + + hr = Cddb_GetICacheManger((void**)&pCache); + if (SUCCEEDED(hr)) + { + hr = pCache->FetchDiscByToc(bstrTOC, ppDisc); + pCache->Release(); + } + + return hr; +} +#endif + +static LRESULT CALLBACK DisplayDiscInfoWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LRESULT result; + HWND hwndListener; + WNDPROC fnOldProc = (WNDPROC)GetPropW(hwnd, L"WNDPROC"); + switch(uMsg) + { + case WM_INITDIALOG: + result = (IsWindowUnicode(hwnd)) ? CallWindowProcW(fnOldProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(fnOldProc, hwnd, uMsg, wParam, lParam); + hwndListener = (HWND)GetPropW(hwnd, L"LISTENER"); + if (hwndListener) CddbProgressDlg_SetStatus(hwndListener, MAKEINTRESOURCEW(IDS_OPENING), -1); + return result; + case WM_DESTROY: + { + RemovePropW(hwnd, L"WNDPROC"); + hwndListener = (HWND)GetPropW(hwnd, L"LISTENER"); + if (hwndListener) + { + RECT rc, rw; + if (GetWindowRect(hwndListener, &rc) && GetWindowRect(hwnd, &rw)) + { + CalculatePopUpPos(&rw, &rc, CENTER_LEFT); + SetWindowPos(hwndListener, NULL, rc.left, rc.top, 0, 0, + SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); + } + } + HWND *list = (HWND*)GetPropW(hwnd, L"WNDLIST"); + RemovePropW(hwnd, L"WNDLIST"); + if (list) + { + for (HWND *p = list; *p != NULL; p++) ShowWindowAsync(*p, SW_SHOWNA); + free(list); + } + RemovePropW(hwnd, L"LISTENER"); + + if (fnOldProc) SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)fnOldProc); + } + break; + case WM_SHOWWINDOW: + if (wParam) + { + hwndListener = (HWND)GetPropW(hwnd, L"LISTENER"); + if(hwndListener) + { + HWND *list = (HWND*)calloc(24, sizeof(HWND)); + if (!FindAllOwnedWindows(hwndListener, list, 24, 0) || !SetPropW(hwnd, L"WNDLIST", list)) free(list); + else for (HWND *p = list; *p != NULL; p++) ShowWindowAsync(*p, SW_HIDE); + ShowWindowAsync(hwndListener, SW_HIDE); + } + } + break; + } + + if (!fnOldProc) + { + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + return (IsWindowUnicode(hwnd)) ? CallWindowProcW(fnOldProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(fnOldProc, hwnd, uMsg, wParam, lParam); +} + +static void CALLBACK OnGrabbed_DisplayDiscInfo(HWND hwnd, CREATESTRUCT *lpcs, HWND *phwndInsertAfter, ULONG_PTR user) +{ + WNDPROC oldProc = (WNDPROC)(LONG_PTR)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)DisplayDiscInfoWndProc); + if (oldProc) + { + SetPropW(hwnd, L"WNDPROC", oldProc); + SetPropW(hwnd, L"LISTENER", (HANDLE)user); + } + if(user) + { + RECT rc, rw; + if (GetClientRect((HWND)user, &rc)) + { + MapWindowPoints((HWND)user, HWND_DESKTOP, (POINT*)&rc, 2); + SetRect(&rw, lpcs->x, lpcs->y, lpcs->x + lpcs->cx, lpcs->y + lpcs->cy); + CalculatePopUpPos(&rc, &rw, CENTER_LEFT); + lpcs->x = rw.left; + lpcs->y = rw.top; + } + } + else ShowWindow((HWND)user, SW_HIDE); +} + +void Cddb_GetResultText(HRESULT hr, LPWSTR pszResult, INT cchResult, LPWSTR pszReason, INT cchReason) +{ + INT nResult, nReason; + + nResult = (S_OK == hr) ? IDS_SUCCESS : IDS_NOT_FOUND; + nReason = 0; + + if (FAILED(hr)) + { + switch(hr) + { + #ifndef IGNORE_API_GRACENOTE + case CDDBCTLNotInitialized: nReason = IDS_CDDB_NOT_INSTALLED; break; + case CDDBCTLBusy: nReason = IDS_CDDB_E_BUSY; break; + case CDDB_E_BADTOC: nReason = IDS_CDDB_E_BADTOC; break; + case E_ABORT: + case CDDBTRNCancelled: + nReason = IDS_CDDB_E_ABORT; break; + #endif + default: nReason = IDS_CDDB_E_FAIL; break; + } + } + + if (pszReason && cchReason) + { + if(nReason) + { INT len; + WASABI_API_LNGSTRINGW_BUF(IDS_REASON, pszReason, cchReason); + len = lstrlenW(pszReason); + cchReason -= len; + WASABI_API_LNGSTRINGW_BUF(nReason, pszReason + len, cchReason); + } + else pszReason[0] = 0x00; + } + + if (pszResult && cchResult) + { + WASABI_API_LNGSTRINGW_BUF(nResult, pszResult, cchResult); + } +} + +static HRESULT Cddb_FinishLookup(MEDIALOOKUP *pLookup, ICddbDisc *pDisc) +{ + HRESULT hr = E_FAIL; + #ifndef IGNORE_API_GRACENOTE + MEDIALOOKUP lookup_cpy; + DWORD delay = AUTOCLOSE_NOW; + + if (!pLookup) hr = E_INVALIDARG; + if (!evntBusy) hr = E_FAIL; + else hr = S_OK; + + if (NULL != pDisc) + pDisc->AddRef(); + + if (NULL != pLookup) + { + CopyMemory(&lookup_cpy, pLookup, sizeof(MEDIALOOKUP)); + SecureZeroMemory(pLookup, sizeof(MEDIALOOKUP)); + } + else + SecureZeroMemory(&lookup_cpy, sizeof(MEDIALOOKUP)); + + if (SUCCEEDED(hr)) + { + HRESULT hrInvoke; + + if(S_OK != lookup_cpy.result) + { + if (NULL != pDisc) + pDisc->Release(); + + pDisc = NULL; + } + + if (lookup_cpy.hwndInfo) + { + CddbProgressDlg_SetExtendedMode(lookup_cpy.hwndInfo, FALSE); + CddbProgressDlg_EnableAbortButton(lookup_cpy.hwndInfo, FALSE); + CddbProgressDlg_SetStatus(lookup_cpy.hwndInfo, MAKEINTRESOURCEW(IDS_PROCESSING), -1); + } + + if (FAILED(lookup_cpy.result)) + delay = 5000; + + hrInvoke = Cddb_InvokeProcessResult(&lookup_cpy, pDisc, &delay); + if (FAILED(hrInvoke) && S_OK == lookup_cpy.result) + lookup_cpy.result = hrInvoke; + } + + SET_BUSY(FALSE); + + if (SUCCEEDED(hr)) + { + if (lookup_cpy.hwndInfo) + { + RECT rc; + if (GetWindowRect(lookup_cpy.hwndInfo, &rc)) + { + g_lastcddbpos.x = rc.left; + g_lastcddbpos.y = rc.top; + } + + lookup_cpy.result = Cddb_DisplayResultDlg(lookup_cpy.hwndInfo, lookup_cpy.result, delay, + CDDB_UI_USE_PARENT | lookup_cpy.flags); + if (delay > 10 && 0 == (CDDB_UI_RESULT_MODAL & lookup_cpy.flags) || FAILED(lookup_cpy.result)) + { + CddbProgressDlg_ExitModal(lookup_cpy.hwndInfo, lookup_cpy.result, FALSE); + } + } + hr = lookup_cpy.result; + } + + if (NULL != lookup_cpy.bstrTOC) + SysFreeString(lookup_cpy.bstrTOC); + + if (lookup_cpy.threadId == GetCurrentThreadId()) + Cddb_UninitializeThread(); + else + { + if (PostThreadMessage(lookup_cpy.threadId, TM_UNINITTHREAD, 0, 0L)) + { + /* MSG msg; + DWORD status; + msg.message = NULL; + for(;;) + { + status = MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); + if (status == WAIT_OBJECT_0+1) + { + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (WM_QUIT == msg.message) break; + if (!CallMsgFilter(&msg, 0)) DispatchMessage(&msg); + } + } + else if (status == WAIT_OBJECT_0) + { + break; + } + } + if (WM_QUIT == msg.message) PostQuitMessage((int)msg.wParam);*/ + } + } + + if (NULL != pDisc) + pDisc->Release(); + #endif + return hr; +} + +static void CALLBACK CddbProgressDlg_OnAbort(HWND hwndDlg, BSTR bstrUser) +{ + #ifndef IGNORE_API_GRACENOTE + ICDDBControl *pControl; + HRESULT hr = Cddb_GetIControl((void**)&pControl); + if (SUCCEEDED(hr)) + { + LONG lVal; + pControl->Cancel(&lVal); + CddbProgressDlg_EnableAbortButton(hwndDlg, FALSE); + pControl->Release(); + } + + //CddbProgressDlg_Completed(hwndDlg, L"Aborted !!!", 4600); + #endif +} + +typedef struct _MODALDATA +{ + ICddbDisc *pDisc; + UINT flags; + BSTR bstrTOC; + +} MODALDATA; + +#ifndef IGNORE_API_GRACENOTE +HRESULT Cddb_DisplayDiscInfo(ICddbDisc *pDisc, CDDBUIFlags *pUIFlags, HWND hwndParent) +{ + HRESULT hr; + ICDDBControl *pControl; + BOOL bManual = FALSE; + hr = Cddb_GetIControl((void**)&pControl); + if (FAILED(hr)) return hr; + + if (hwndParent) + { + if (!BeginGrabCreateWindow(L"#32770", NULL, NULL, OnGrabbed_DisplayDiscInfo, (ULONG_PTR)hwndParent)) + { + ShowWindow(hwndParent, SW_HIDE); + bManual = TRUE; + } + } + + hr = pControl->DisplayDiscInfo(pDisc, *pUIFlags, pUIFlags); + if (hwndParent) + { + EndGrabCreateWindow(); + if (bManual) ShowWindow(hwndParent, SW_SHOW); + } + + return hr; +} + +static void CALLBACK CddbProgressDlg_OnSubmitNew(HWND hwndDlg, BSTR bstrUser) +{ + HRESULT hr; + ICDDBControl *pControl; + CDDBUIFlags uiflags; + MODALDATA *pData; + wchar_t szText[256] = {0}; + + pData = (MODALDATA*)CddbProgressDlg_GetUserData(hwndDlg); + if (!pData) + { + CddbProgressDlg_ExitModal(hwndDlg, E_INVALIDARG, TRUE); + return; + } + + CddbProgressDlg_ShowButton1(hwndDlg, NULL, NULL, NULL); + + SetWindowText(hwndDlg, WASABI_API_LNGSTRINGW_BUF(IDS_SUBMITDISC_TITLE, szText, sizeof(szText)/sizeof(wchar_t))); + CddbProgressDlg_Initialize(hwndDlg, MAKEINTRESOURCEW(IDS_QUERYING), CddbProgressDlg_OnAbort, NULL); + CddbProgressDlg_SetStatus(hwndDlg, MAKEINTRESOURCEW(IDS_INITIALIZING), -1); + + hr = Cddb_GetIControl((void**)&pControl); + if (SUCCEEDED(hr)) + { + hr = pControl->GetSubmitDisc(pData->bstrTOC, NULL, NULL, &pData->pDisc); + pControl->Release(); + } + + if (!pData->pDisc) + { + CddbProgressDlg_ExitModal(hwndDlg, hr, TRUE); + return; + } + + uiflags = (CDDBUIFlags)(UI_SUBMITNEW | UI_EDITMODE); + hr = Cddb_DisplayDiscInfo(pData->pDisc, &uiflags, hwndDlg); + + if (SUCCEEDED(hr) && (0 == ((uiflags & (UI_OK | UI_DATA_CHANGED)) == (UI_OK | UI_DATA_CHANGED)))) + hr = S_FALSE; + + if (S_OK != hr) + { + pData->pDisc->Release(); + pData->pDisc = NULL; + } + CddbProgressDlg_ExitModal(hwndDlg, hr, TRUE); + return; +} + +static void CALLBACK CddbProgressDlg_OnAcceptMatch(HWND hwndDlg, BSTR bstrUser) +{ + MODALDATA *pData; + pData = (MODALDATA*)CddbProgressDlg_GetUserData(hwndDlg); + if (!pData) + { + CddbProgressDlg_ExitModal(hwndDlg, E_INVALIDARG, TRUE); + return; + } + + pData->pDisc = (ICddbDisc*)(LONG_PTR)(LONG)(CddbProgressDlg_GetSelRecordIndex(hwndDlg) + 1); + CddbProgressDlg_ExitModal(hwndDlg, S_OK, TRUE); + return; +} +#endif + +HRESULT Cddb_DoLookup(LPCWSTR pszTOC, HWND hwndParent, CDDB_CB callback, UINT flags, ULONG_PTR user) +{ + #ifndef IGNORE_API_GRACENOTE + HRESULT hr; + + ICDDBControl *pControl; + CDDBMatchCode matchCode; + + if (!callback) return E_INVALIDARG; + + if (IS_BUSY(0)) + { + return (CSTR_EQUAL == CompareStringW(INVARIANT_LCID, 0, g_lookup.bstrTOC, -1, pszTOC, -1)) ? E_PENDING : CDDBCTLBusy; + } + + hr = Cddb_InitializeThread(); + if (FAILED(hr)) return hr; + + SET_BUSY(TRUE); + CLEARLOOKUP(); + + g_lookup.callback = callback; + g_lookup.user = user; + g_lookup.flags = flags; + g_lookup.threadId = GetCurrentThreadId(); + g_lookup.bstrTOC = SysAllocString(pszTOC); + eventMngr.SetUserParam((ULONG_PTR)&g_lookup); + + if (0 == (CDDB_NOCACHE & flags)) + { + ICddbDisc *pDisc; + g_lookup.result = Cddb_GetDiscFromCache(g_lookup.bstrTOC, &pDisc); + if (CDDBTRNDataStoreNotCached != g_lookup.result) + { + Cddb_FinishLookup(&g_lookup, pDisc); + if (pDisc) pDisc->Release(); + return S_OK; + } + } + + if (CDDB_NOINET == (CDDB_NOINET & flags)) + { + g_lookup.result = S_FALSE; + Cddb_FinishLookup(&g_lookup, NULL); + return S_OK; + } + + hwndParent = GetAdaptedParent(hwndParent); + + g_lookup.hwndInfo = CddbProgressDlg_Create(hwndParent, SW_HIDE); + hwndProgressListener = g_lookup.hwndInfo; + + CddbProgressDlg_Initialize(g_lookup.hwndInfo, MAKEINTRESOURCEW(IDS_QUERYING), CddbProgressDlg_OnAbort, NULL); + CddbProgressDlg_SetStatus(g_lookup.hwndInfo, MAKEINTRESOURCEW(IDS_INITIALIZING), -1); + + if (g_lookup.hwndInfo) + { + SetPopUpPos(g_lookup.hwndInfo, CENTER_LEFT); + ShowWindow(g_lookup.hwndInfo, SW_SHOWNA); + } + + g_lookup.result = Cddb_GetIControl((void**)&pControl); + if (FAILED(g_lookup.result)) + { + Cddb_FinishLookup(&g_lookup, NULL); + return S_OK; + } + + g_lookup.result = pControl->LookupMediaByToc(g_lookup.bstrTOC, TRUE, &matchCode); + + pControl->Release(); + if (FAILED(g_lookup.result)) + { + Cddb_FinishLookup(&g_lookup, NULL); + return S_OK; + } + + if (CDDB_UI_MODAL & flags) + { + RECT rc; + + hr = CddbProgressDlg_DoModal(g_lookup.hwndInfo, &rc); + if (SUCCEEDED(hr)) + { + SET_BUSY(FALSE); + CLEARLOOKUP(); + + g_lastcddbpos.x = rc.left; + g_lastcddbpos.y = rc.top; + } + } + return S_OK; + #else + return E_FAIL; + #endif +} + +static HRESULT Cddb_DoSubmitNewDlg(HWND hwndCaller, BSTR bstrTOC, UINT flags, ICddbDisc **ppDisc) +{ + RECT rw; + HRESULT hr; + HWND hwndInfo, hwndOldListener, hwndParent; + MODALDATA data; + wchar_t szText[256] = {0}; + + if (!ppDisc) return E_INVALIDARG; + + data.pDisc = NULL; + data.bstrTOC = bstrTOC; + data.flags = flags; + + hwndParent = (hwndCaller) ? GetParent(hwndCaller) : NULL; + if (!hwndParent) hwndParent = line.hMainWindow; + hwndInfo = CddbProgressDlg_Create(hwndParent, SW_HIDE); + + if (!hwndInfo || !CddbProgressDlg_SetUserData(hwndInfo, &data)) + { + if (hwndInfo) + DestroyWindow(hwndInfo); + + if (NULL != data.bstrTOC) + SysFreeString(data.bstrTOC); + return E_FAIL; + } + + SetWindowText(hwndInfo, WASABI_API_LNGSTRINGW_BUF(IDS_LOOKUPRESULT_TITLE, szText, sizeof(szText)/sizeof(wchar_t))); + CddbProgressDlg_Initialize(hwndInfo, MAKEINTRESOURCEW(IDS_NOT_FOUND), NULL, NULL); + CddbProgressDlg_Completed(hwndInfo, MAKEINTRESOURCEW(IDS_SUBMIT_OFFER), NULL, AUTOCLOSE_NEVER, S_OK); + #ifndef IGNORE_API_GRACENOTE + CddbProgressDlg_ShowButton1(hwndInfo, MAKEINTRESOURCEW(IDS_SUBMITNEW), CddbProgressDlg_OnSubmitNew, NULL); + #endif + + hwndOldListener = hwndProgressListener; + if (hwndCaller) + { + GetWindowRect(hwndCaller, &rw); + SetWindowPos(hwndInfo, HWND_TOP, rw.left, rw.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); + ShowWindowAsync(hwndCaller, SW_HIDE); + } + else ShowWindow(hwndInfo, SW_SHOW); + + RECT rc; + hr = CddbProgressDlg_DoModal(hwndInfo, &rc); + + *ppDisc = data.pDisc; + + if (hwndCaller) + { + SetWindowPos(hwndCaller, HWND_TOP, rc.left, rc.top, 0, 0, SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOSIZE | SWP_SHOWWINDOW); + } + + hwndProgressListener = hwndOldListener; + return hr; +} + +#ifndef IGNORE_API_GRACENOTE +static HRESULT Cddb_DoFuzzyMatchDlg(HWND hwndCaller, UINT flags, ICddbDiscs *pDiscs, LONG *plVal) +{ + HRESULT hr; + LONG count; + ICddbDisc *pDisc(NULL); + BSTR bstrArtist, bstrTitle; + RECT rw; + HWND hwndInfo, hwndOldListener, hwndParent; + MODALDATA data; + wchar_t szText[256] = {0}; + + data.pDisc = NULL; + data.flags = flags; + + if (!plVal || !pDiscs) return E_INVALIDARG; + *plVal = 0L; + + hwndParent = (hwndCaller) ? GetParent(hwndCaller) : NULL; + if (!hwndParent) hwndParent = line.hMainWindow; + hwndInfo = CddbProgressDlg_Create(hwndParent, SW_HIDE); + + if (!hwndInfo || !CddbProgressDlg_SetUserData(hwndInfo, &data)) + { + if (hwndInfo) DestroyWindow(hwndInfo); + return E_FAIL; + } + + hwndOldListener = hwndProgressListener; + + SetWindowText(hwndInfo, WASABI_API_LNGSTRINGW_BUF(IDS_LOOKUPRESULT_TITLE, szText, sizeof(szText)/sizeof(wchar_t))); + CddbProgressDlg_Initialize(hwndInfo, MAKEINTRESOURCEW(IDS_FUZZYDISC_TITLE), NULL, NULL); + CddbProgressDlg_SetStatus(hwndInfo, MAKEINTRESOURCEW(IDS_INITIALIZING), -1); + + if (hwndCaller) + { + GetWindowRect(hwndCaller, &rw); + SetWindowPos(hwndInfo, HWND_TOP, rw.left, rw.top, 0, 0, SWP_NOSIZE); + ShowWindowAsync(hwndCaller, SW_HIDE); + } + ShowWindow(hwndInfo, SW_SHOWNA); + + if (FAILED(pDiscs->get_Count(&count))) count = 0; + for(long i = 1; i <= count; i++) + { + if (SUCCEEDED(pDiscs->GetDisc(i, &pDisc))) + { + if (FAILED(pDisc->get_Artist(&bstrArtist))) bstrArtist = NULL; + if (FAILED(pDisc->get_Title(&bstrTitle))) bstrTitle = NULL; + CddbProgressDlg_AddRecord(hwndInfo, bstrArtist, bstrTitle, NULL); + if (bstrArtist) SysFreeString(bstrArtist); + if (bstrTitle) SysFreeString(bstrTitle); + pDisc->Release(); + } + } + + CddbProgressDlg_ShowButton1(hwndInfo, MAKEINTRESOURCEW(IDS_ACCEPT), CddbProgressDlg_OnAcceptMatch, NULL); + CddbProgressDlg_SetExtendedMode(hwndInfo, TRUE); + CddbProgressDlg_Completed(hwndInfo, MAKEINTRESOURCEW(IDS_FOUND_MULTIPLE), NULL, AUTOCLOSE_NEVER, S_OK); + + UpdateWindow(hwndInfo); + SetForegroundWindow(hwndInfo); + + RECT rc; + hr = CddbProgressDlg_DoModal(hwndInfo, &rc); + g_lastcddbpos.x = rc.left; + g_lastcddbpos.y = rc.top; + *plVal = ((LONG)(LONG_PTR)data.pDisc); + + if (hwndCaller) + { + SetWindowPos(hwndCaller, HWND_TOP, rc.left, rc.top, 0, 0, SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOSIZE | SWP_SHOWWINDOW); + } + hwndProgressListener = hwndOldListener; + return hr; +} +#endif + +static void CALLBACK Cddb_OnCommandCompleted(LONG lCommandCode, HRESULT hCommandResult, VARIANT *pCommandData, UINT_PTR user) +{ + #ifndef IGNORE_API_GRACENOTE + switch(lCommandCode) + { + case CMD_LookupMediaByToc: Cddb_OnMediaLookupCompleted(hCommandResult, (CDDBMatchCode)pCommandData->lVal, (MEDIALOOKUP*)user); break; + case CMD_GetFullDiscInfo: Cddb_OnGetFullDiscInfoCompleted(hCommandResult, (ICddbDisc*)pCommandData->byref, (MEDIALOOKUP*)user); break; + case CMD_SubmitDisc: Cddb_OnSubmitDiscCompleted(hCommandResult, (MEDIALOOKUP*)user); break; + } + #endif +} + +static void CALLBACK Cddb_OnCommandProgress(LONG lCommandCode, LONG lProgressCode, LONG lBytesDone, LONG lBytesTotal, UINT_PTR user) +{ + #ifndef IGNORE_API_GRACENOTE + if (hwndProgressListener) + { + INT ids(0), nComplete(-1); + switch(lProgressCode) + { + case CMD_CONNECTING: ids = IDS_CDDB_PROGRESS_CONNECTING; break; + case CMD_SENDING: ids = IDS_CDDB_PROGRESS_SENDING; nComplete = lBytesTotal?((100 * lBytesDone)/lBytesTotal):100; break; + case CMD_RECEIVING: ids = IDS_CDDB_PROGRESS_RECEIVING; nComplete = lBytesTotal?((100 * lBytesDone)/lBytesTotal):100; break; + case CMD_CANCELLED: ids = IDS_CDDB_PROGRESS_CANCELLED; break; + case CMD_WAITING: ids = IDS_CDDB_PROGRESS_WAITING; lBytesTotal?((100 * lBytesDone)/lBytesTotal):100; break; + case CMD_COMPLETED: ids = IDS_CDDB_PROGRESS_COMPLETED; break; + } + if (ids) CddbProgressDlg_SetStatus(hwndProgressListener, MAKEINTRESOURCEW(ids), nComplete); + } + #endif +} + +#ifndef IGNORE_API_GRACENOTE +static void Cddb_OnMediaLookupCompleted(HRESULT result, CDDBMatchCode matchCode, MEDIALOOKUP *pLookup) +{ + ICDDBControl *pControl; + ICddbDisc *pDisc(NULL), *pfuzzyDisc(NULL); + ICddbDiscs *pDiscs(NULL); + LONG lVal; + wchar_t szText[256] = {0}; + if (!pLookup) return; + + SetWindowText(pLookup->hwndInfo, WASABI_API_LNGSTRINGW_BUF(IDS_LOOKUPRESULT_TITLE, szText, sizeof(szText)/sizeof(wchar_t))); + pLookup->result = result; + if (FAILED(pLookup->result)) + { + switch(pLookup->result) + { + case CDDBSVCServiceError: pLookup->result = CDDB_E_BADTOC; break;// + } + Cddb_FinishLookup(pLookup, NULL); + return; + } + + pLookup->result = Cddb_GetIControl((void**)&pControl); + if (FAILED(pLookup->result)) + { + Cddb_FinishLookup(pLookup, NULL); + return; + } + + switch(matchCode) + { + case MATCH_EXACT: + CddbProgressDlg_SetStatus(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_FOUND_EXACT), -1); + pLookup->result = pControl->GetMatchedDiscInfo((IUnknown**)&pDisc); + break; + case MATCH_MULTIPLE: + pLookup->result = S_MULTIPLE; + CddbProgressDlg_SetStatus(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_FOUND_MULTIPLE), -1); + if (0 != ((CDDB_UI_MULTIPLE | CDDB_RESOLVE_MULTIPLE) & pLookup->flags)) + { + lVal = 0; + pLookup->result = pControl->GetMatchedDiscInfo((IUnknown**)&pDiscs); + if (SUCCEEDED(pLookup->result)) + { + if (0 != (CDDB_UI_MULTIPLE & pLookup->flags)) + { + pLookup->result = Cddb_DoFuzzyMatchDlg(pLookup->hwndInfo, 0, pDiscs, &lVal); + if (S_OK != pLookup->result) lVal = 0; + } + if (0 == lVal && 0 != (CDDB_RESOLVE_MULTIPLE & pLookup->flags)) lVal = 1; + if (lVal) + { + CddbProgressDlg_Initialize(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_QUERYING), CddbProgressDlg_OnAbort, NULL); + CddbProgressDlg_SetStatus(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_INITIALIZING), -1); + pLookup->result = pDiscs->GetDisc(lVal, &pfuzzyDisc); + if (SUCCEEDED(pLookup->result)) + { + if (!pfuzzyDisc) pLookup->result = S_FALSE; + else + { + pLookup->result = pfuzzyDisc->IsSubmit(&lVal); + if (FAILED(pLookup->result) || !lVal) + { + pLookup->result = pControl->GetFullDiscInfo(pfuzzyDisc, TRUE, &pDisc); + pfuzzyDisc->Release(); + if (SUCCEEDED(pLookup->result)) + { + pDiscs->Release(); + pControl->Release(); + return; + } + } + else pDisc = pfuzzyDisc; + } + } + } + pDiscs->Release(); + } + } + break; + case MATCH_NONE: + pLookup->result = S_FALSE; + CddbProgressDlg_SetStatus(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_NOT_FOUND), -1); + if (CDDB_UI_NOMATCH & pLookup->flags) + { + pLookup->result = Cddb_DoSubmitNewDlg(pLookup->hwndInfo, pLookup->bstrTOC, 0, &pDisc); + if (S_OK == pLookup->result) + { + LONG lVal; + CddbProgressDlg_Initialize(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_SUBMITTING), CddbProgressDlg_OnAbort, NULL); + CddbProgressDlg_SetStatus(pLookup->hwndInfo, MAKEINTRESOURCEW(IDS_INITIALIZING), -1); + + pSubmitDisc = pDisc; + pLookup->result = pControl->SubmitDisc(pSubmitDisc, TRUE, &lVal); + if (SUCCEEDED(pLookup->result)) + { + pControl->Release(); + return; + } + + } + } + break; + } + pControl->Release(); + + Cddb_FinishLookup(pLookup, pDisc); + if (pDisc) pDisc->Release(); +} +#endif + +static void Cddb_OnGetFullDiscInfoCompleted(HRESULT result, ICddbDisc *pDisc, MEDIALOOKUP *pLookup) +{ + if (!pLookup) return; + pLookup->result = result; + Cddb_FinishLookup(pLookup, pDisc); +} + +static void Cddb_OnSubmitDiscCompleted(HRESULT result, MEDIALOOKUP *pLookup) +{ + #ifndef IGNORE_API_GRACENOTE + if (!pLookup) return; + pLookup->result = result; + if (FAILED(result)) + { + if (pSubmitDisc) pSubmitDisc->Release(); + pSubmitDisc = NULL; + } + Cddb_FinishLookup(pLookup, pSubmitDisc); + if (pSubmitDisc) + { + pSubmitDisc->Release(); + pSubmitDisc = NULL; + } + #endif +} + +HWND Cddb_GetInfoWindow(void) +{ + #ifndef IGNORE_API_GRACENOTE + return (IS_BUSY(0)) ? g_lookup.hwndInfo : NULL; + #else + return NULL; + #endif +} + +void Cdbb_DisplayInfo(LPCWSTR pszTitle, LPCWSTR pszCaption, LPCWSTR pszStatus, INT percentCompleted) +{ + HWND hwndInfo; + hwndInfo = Cddb_GetInfoWindow(); + if (!hwndInfo) return; + BOOL CddbProgressDlg_SetStatus(HWND hwnd, LPCWSTR pszStatus, INT nPercentCompleted); +} + +HRESULT Cddb_DisplayResultDlg(HWND hwndParent, HRESULT result, DWORD dwAutoCloseDelay, UINT flags) +{ + #ifndef IGNORE_API_GRACENOTE + HWND hwndInfo; + wchar_t szReason[256] = {0}, szResult[256] = {0}; + + if (CDDB_UI_USE_PARENT & flags) hwndInfo = hwndParent; + else + { + wchar_t szText[256] = {0}; + hwndParent = GetAdaptedParent(hwndParent); + hwndInfo = CddbProgressDlg_Create(hwndParent, SW_HIDE); + SetPopUpPos(hwndInfo, CENTER_LEFT); + + SetWindowText(hwndInfo, WASABI_API_LNGSTRINGW_BUF(IDS_LOOKUPRESULT_TITLE, szText, sizeof(szText)/sizeof(wchar_t))); + CddbProgressDlg_Initialize(hwndInfo, NULL, NULL, NULL); + CddbProgressDlg_Completed(hwndInfo, NULL, NULL, AUTOCLOSE_NEVER, S_OK); + } + if (!hwndInfo || !IsWindow(hwndInfo)) return E_FAIL; + + if (AUTOCLOSE_NOW == dwAutoCloseDelay && GetWindowThreadProcessId(hwndInfo, NULL) != GetCurrentThreadId()) + { + dwAutoCloseDelay = 1; // DestroyWindow is not working on other thread + ShowWindowAsync(hwndInfo, SW_HIDE); // in case we in modal loop on other + } + + if (dwAutoCloseDelay > 10) + { + Cddb_GetResultText(result, szResult, sizeof(szResult)/sizeof(wchar_t), + szReason, sizeof(szReason)/sizeof(wchar_t)); + ShowWindow(hwndInfo, SW_SHOW); + } + + CddbProgressDlg_Completed(hwndInfo, szResult, szReason, dwAutoCloseDelay, result); + + if (dwAutoCloseDelay > 10 && CDDB_UI_RESULT_MODAL == ((CDDB_UI_MODAL | CDDB_UI_RESULT_MODAL) & flags)) + { + CddbProgressDlg_DoModal(hwndInfo, NULL); + } + #endif + + return S_OK; +}
\ No newline at end of file |