winamp/Src/Plugins/Input/in_cdda/CDDB.Cpp

1709 lines
44 KiB
C++

#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 &copy)
{
operator =(copy);
}
TRACKINFO &TRACKINFO::operator =(const TRACKINFO &copy)
{
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 &copy)
{
operator =(copy);
}
DINFO &DINFO::operator =(const DINFO &copy)
{
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;
}