Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
598
Src/Plugins/Input/in_cdda/Main.cpp
Normal file
598
Src/Plugins/Input/in_cdda/Main.cpp
Normal file
|
@ -0,0 +1,598 @@
|
|||
//#define PLUGIN_NAME "Nullsoft CD Plug-in"
|
||||
#define PLUGIN_VERSION L"4.7"
|
||||
|
||||
#include "main.h"
|
||||
#include "cddb.h"
|
||||
|
||||
#include "CDPlay.h"
|
||||
#include "DAEPlay.h"
|
||||
#include "MCIPlay.h"
|
||||
#include "WindacPlay.h"
|
||||
|
||||
#include "PlayStatus.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "../Winamp/strutil.h"
|
||||
#include "../winamp/wa_ipc.h"
|
||||
#include <shlwapi.h>
|
||||
#include "api__in_cdda.h"
|
||||
#include "workorder.h"
|
||||
#include <strsafe.h>
|
||||
using namespace Nullsoft::Utility;
|
||||
Nullsoft::Utility::LockGuard *playDeviceGuard = 0;
|
||||
char * s_last_error = NULL;
|
||||
|
||||
static wchar_t playDriveLetter;
|
||||
//extern int config_maxextractspeed;
|
||||
api_config *AGAVE_API_CONFIG=0;
|
||||
|
||||
#ifndef _DEBUG
|
||||
BOOL WINAPI _DllMainCRTStartup(HINSTANCE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
DisableThreadLibraryCalls(hInst);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IGNORE_API_GRACENOTE
|
||||
static DINFO g_ps;
|
||||
#endif
|
||||
int g_ps_inuse = 0;
|
||||
int g_playtrack, g_playlength;
|
||||
wchar_t lastfn[1024] = {0};
|
||||
int paused;
|
||||
void _setvolume();
|
||||
DWORD MainThreadId;
|
||||
|
||||
extern char INI_FILE[];
|
||||
extern char app_name[];
|
||||
|
||||
int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
|
||||
{
|
||||
MSGBOXPARAMS msgbx = {sizeof(MSGBOXPARAMS),0};
|
||||
msgbx.lpszText = message;
|
||||
msgbx.lpszCaption = title;
|
||||
msgbx.lpszIcon = MAKEINTRESOURCE(102);
|
||||
msgbx.hInstance = GetModuleHandle(0);
|
||||
msgbx.dwStyle = MB_USERICON;
|
||||
msgbx.hwndOwner = parent;
|
||||
return MessageBoxIndirect(&msgbx);
|
||||
}
|
||||
|
||||
void about(HWND hwndParent)
|
||||
{
|
||||
wchar_t message[1024] = {0}, text[1024] = {0};
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_CD_PLUGIN_OLD,text,1024);
|
||||
StringCchPrintf(message, 1024, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT),
|
||||
line.description, TEXT(__DATE__));
|
||||
DoAboutMessageBox(hwndParent,text,message);
|
||||
}
|
||||
|
||||
void quit();
|
||||
int init();
|
||||
|
||||
int isourfile(const in_char *fn)
|
||||
{
|
||||
if (!_wcsnicmp(fn, L"cda://", 6)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
volatile int done = 0;
|
||||
|
||||
int g_lastpos = 0;
|
||||
C_CDPlay *g_cdplay = 0;
|
||||
|
||||
const wchar_t *filename(const wchar_t *fn)
|
||||
{
|
||||
const wchar_t *s = scanstr_backcW(fn, L"\\/", 0);
|
||||
if (!s) return fn;
|
||||
return (s + 1);
|
||||
}
|
||||
|
||||
bool ParseName(const wchar_t *fn, wchar_t &device, int &trackNum)
|
||||
{
|
||||
wchar_t track[16] = L"1";
|
||||
if (!_wcsnicmp(fn, L"cda://", 6))
|
||||
{
|
||||
fn += 6;
|
||||
wchar_t d[16] = {0};
|
||||
wchar_t *p = d;
|
||||
while (fn && *fn && *fn != L',' && (p - d < 15)) *p++ = *fn++;
|
||||
if (p) *p = 0;
|
||||
device = toupper(d[0]);
|
||||
if (*fn == L',') fn++;
|
||||
lstrcpyn(track, fn, ARRAYSIZE(track));
|
||||
trackNum = _wtoi(track);
|
||||
return true;
|
||||
}
|
||||
else if (!_wcsicmp(extensionW(fn), L"cda"))
|
||||
{
|
||||
const wchar_t *f = filename(fn);
|
||||
if (!_wcsnicmp(f, L"track", 5)) f += 5;
|
||||
wchar_t t[16] = {0};
|
||||
wchar_t *p = t;
|
||||
while (f && *f && *f != L'.' && (p - t < 15)) *p++ = *f++;
|
||||
lstrcpyn(track, t, ARRAYSIZE(track));
|
||||
device = toupper(fn[0]);
|
||||
trackNum = _wtoi(track);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
WindacPlay *windacPlayer = 0;
|
||||
DAEPlay *daePlayer = 0;
|
||||
MciPlay *mciPlayer = 0;
|
||||
|
||||
int play(const in_char *fn)
|
||||
{
|
||||
done = 0;
|
||||
lstrcpyn(lastfn, fn, 1024);
|
||||
line.is_seekable = 0;
|
||||
g_lastpos = 0;
|
||||
|
||||
int track = -1;
|
||||
if (!ParseName(fn, playDriveLetter, track))
|
||||
return 1;
|
||||
|
||||
if (playStatus[playDriveLetter].IsRipping() || (g_cdplay && g_cdplay->IsPlaying(playDriveLetter)))
|
||||
{
|
||||
wchar_t title[32] = {0};
|
||||
MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_CD_CURRENTLY_IN_USE),
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_DRIVE_IN_USE,title,32), MB_OK);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (g_cdplay) delete g_cdplay; g_cdplay = NULL;
|
||||
|
||||
//first, try DAE
|
||||
if (!daePlayer) daePlayer = new DAEPlay;
|
||||
g_cdplay = daePlayer;
|
||||
|
||||
int ret = (g_cdplay ? g_cdplay->play(playDriveLetter, track) : 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
if (g_cdplay) delete g_cdplay; g_cdplay = daePlayer = NULL;
|
||||
|
||||
//second, try Windac
|
||||
if (!windacPlayer) windacPlayer = new WindacPlay;
|
||||
g_cdplay = windacPlayer;
|
||||
ret = (g_cdplay ? g_cdplay->play(playDriveLetter, track) : 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
if (g_cdplay) delete g_cdplay; g_cdplay = windacPlayer = NULL;
|
||||
|
||||
//try MCI
|
||||
if (!mciPlayer) mciPlayer = new MciPlay;
|
||||
g_cdplay = mciPlayer;
|
||||
int ret = (g_cdplay ? g_cdplay->play(playDriveLetter, track) : 1);
|
||||
if (ret != 0)
|
||||
{
|
||||
//no luck
|
||||
if (g_cdplay) delete g_cdplay; g_cdplay = mciPlayer = NULL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
paused = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void pause()
|
||||
{
|
||||
if (g_cdplay) g_cdplay->pause();
|
||||
paused = 1;
|
||||
}
|
||||
void unpause()
|
||||
{
|
||||
if (g_cdplay) g_cdplay->unpause();
|
||||
paused = 0;
|
||||
}
|
||||
int ispaused()
|
||||
{
|
||||
return paused;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
if (g_cdplay)
|
||||
{
|
||||
g_cdplay->stop();
|
||||
g_cdplay = NULL;
|
||||
}
|
||||
|
||||
done = 0;
|
||||
line.SAVSADeInit();
|
||||
}
|
||||
|
||||
int getlength()
|
||||
{
|
||||
if (g_cdplay) return g_cdplay->getlength();
|
||||
return -1000;
|
||||
}
|
||||
|
||||
int getoutputtime()
|
||||
{
|
||||
if (g_cdplay) return g_cdplay->getoutputtime();
|
||||
return 0;
|
||||
//return audioGetPos();
|
||||
}
|
||||
void setoutputtime(int time_in_ms)
|
||||
{
|
||||
if (g_cdplay) g_cdplay->setoutputtime(time_in_ms);
|
||||
}
|
||||
|
||||
void setvolume(int volume)
|
||||
{
|
||||
if (volume != -666)
|
||||
{
|
||||
a_v = volume;
|
||||
}
|
||||
if (g_cdplay) g_cdplay->setvolume(a_v, a_p);
|
||||
}
|
||||
|
||||
void setpan(int pan)
|
||||
{
|
||||
a_p = pan;
|
||||
if (g_cdplay) g_cdplay->setvolume(a_v, a_p);
|
||||
}
|
||||
|
||||
int infoDlg(const in_char *fn, HWND hwnd)
|
||||
{
|
||||
return 0;
|
||||
#if 0 // switched to unified file info dialog in 5.53
|
||||
if (!_stricmp(extension(fn), "cda") || !_strnicmp(fn, "cda://", 6))
|
||||
{
|
||||
if (!g_ps_inuse)
|
||||
{
|
||||
char device;
|
||||
int res=1;
|
||||
MCIDEVICEID d = 0;
|
||||
g_ps_inuse = 1;
|
||||
device = fn[_strnicmp(fn, "cda://", 6) ? 0 : 6];
|
||||
if (device >= 'a' && device <= 'z') device += 'A' -'a';
|
||||
|
||||
CDOpen(&d, device, L"infoDlg");
|
||||
memset(&g_ps, 0, sizeof(g_ps));
|
||||
res = GetDiscID(d, &g_ps);
|
||||
CDClose(&d);
|
||||
if (!res)
|
||||
res = GetCDDBInfo(&g_ps, device);
|
||||
|
||||
//if (!res) DBEdit(&g_ps, hwnd, 0, device);
|
||||
//if (!res)
|
||||
{
|
||||
if (CDEdit(device, &g_ps, hwnd))
|
||||
{
|
||||
g_ps_inuse = 0;
|
||||
return INFOBOX_EDITED;
|
||||
}
|
||||
}
|
||||
g_ps_inuse = 0;
|
||||
}
|
||||
}
|
||||
return INFOBOX_UNCHANGED;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void getfileinfo(const in_char *filename, in_char *title, int *length_in_ms)
|
||||
{
|
||||
#if 0
|
||||
int track;
|
||||
char device;
|
||||
MCIDEVICEID dev2 = 0;
|
||||
if (length_in_ms) *length_in_ms = -1000;
|
||||
|
||||
if (!filename || !*filename) // currently playing
|
||||
{
|
||||
if (!_stricmp(extension(lastfn), "cda") || !_strnicmp(lastfn, "cda://", 6))
|
||||
{
|
||||
#ifdef IGNORE_API_GRACENOTE
|
||||
if (title)
|
||||
{
|
||||
lstrcpynA(title, "CD Track", GETFILEINFO_TITLE_LENGTH);
|
||||
if (!g_ps_inuse)
|
||||
{
|
||||
g_ps_inuse = 1;
|
||||
memset(&g_ps, 0, sizeof(g_ps));
|
||||
|
||||
if (CDOpen(&dev2, playDriveLetter, L"getfileinfo"))
|
||||
{
|
||||
wchar_t wtitle[256] = {0};
|
||||
int ret = GetDiscID(dev2, &g_ps);
|
||||
CDClose(&dev2);
|
||||
if (!ret && GetCDDBInfo(&g_ps, 0)) // TODO: get device letter
|
||||
PostMessage(line.hMainWindow, WM_USER, (WPARAM) L"cda://", 247/*IPC_REFRESHPLCACHE*/);
|
||||
if (wtitle[0])
|
||||
lstrcpynA(title, AutoChar(wtitle), GETFILEINFO_TITLE_LENGTH);
|
||||
|
||||
}
|
||||
g_ps_inuse = 0;
|
||||
}
|
||||
}
|
||||
if (length_in_ms) *length_in_ms = g_playlength;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
if (title)
|
||||
{
|
||||
const char *p = filename + strlen(filename);
|
||||
while (p >= filename && *p != '\\') p--;
|
||||
lstrcpynA(title, ++p, GETFILEINFO_TITLE_LENGTH);
|
||||
}
|
||||
track = 0;
|
||||
|
||||
if (!_strnicmp(filename, "cda://", 6)) // determine length of cd track via MCI
|
||||
{
|
||||
track = atoi(filename + 8);
|
||||
device = filename[6];
|
||||
if (device >= 'a' && device <= 'z') device += 'A' -'a';
|
||||
|
||||
if (length_in_ms)
|
||||
{
|
||||
if (CDOpen(&dev2, device, L"getfileinfo"))
|
||||
{
|
||||
MCI_SET_PARMS sMCISet;
|
||||
sMCISet.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
|
||||
MCISendCommand(dev2, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet);
|
||||
*length_in_ms = CDGetTrackLength(dev2, track);
|
||||
sMCISet.dwTimeFormat = MCI_FORMAT_TMSF;
|
||||
MCISendCommand(dev2, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &sMCISet);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // determine from RIFF structure of .CDA
|
||||
{
|
||||
HMMIO hmmio;
|
||||
hmmio = mmioOpenA((char *)filename, NULL, MMIO_READ | MMIO_ALLOCBUF);
|
||||
device = filename[0];
|
||||
if (device >= 'a' && device <= 'z') device += 'A' -'a';
|
||||
if (hmmio)
|
||||
{
|
||||
MMCKINFO mmckinfoParent; // parent chunk information
|
||||
mmckinfoParent.fccType = mmioFOURCC('C', 'D', 'D', 'A');
|
||||
if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent, NULL, MMIO_FINDRIFF) == MMSYSERR_NOERROR)
|
||||
{
|
||||
MMCKINFO mmckinfoSubchunk; // subchunk information structure
|
||||
mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
|
||||
if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK) == MMSYSERR_NOERROR)
|
||||
{
|
||||
char *format;
|
||||
DWORD dwFmtSize; // size of "FMT" chunk
|
||||
dwFmtSize = mmckinfoSubchunk.cksize;
|
||||
format = (char *) GlobalAlloc(GPTR, dwFmtSize);
|
||||
if (mmioRead(hmmio, (HPSTR) format, dwFmtSize) == (int)dwFmtSize)
|
||||
{
|
||||
mmioAscend(hmmio, &mmckinfoSubchunk, 0);
|
||||
track = *((short int *)format + 1);
|
||||
if (length_in_ms)
|
||||
{
|
||||
int length = *((int *)format + 3);
|
||||
int l = length % 75;
|
||||
length /= 75;
|
||||
length *= 1000;
|
||||
length += (l * 1000) / 75;
|
||||
*length_in_ms = length;
|
||||
}
|
||||
}
|
||||
GlobalFree(format);
|
||||
}
|
||||
}
|
||||
mmioClose(hmmio, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGNORE_API_GRACENOTE
|
||||
if (title && track)
|
||||
{
|
||||
if (0 && !g_ps_inuse)
|
||||
{
|
||||
g_ps_inuse = 1;
|
||||
memset(&g_ps, 0, sizeof(g_ps));
|
||||
if (!dev2)
|
||||
{
|
||||
CDOpen(&dev2, device, L"getfileinfo");
|
||||
}
|
||||
if (dev2)
|
||||
{
|
||||
StringCchPrintfA(title, GETFILEINFO_TITLE_LENGTH, "CD Track %d", track);
|
||||
wchar_t wtitle[256] = L"";
|
||||
int ret = GetDiscID(dev2, &g_ps);
|
||||
CDClose(&dev2);
|
||||
dev2=0;
|
||||
if (!ret && GetCDDBInfo(&g_ps, device))
|
||||
PostMessage(line.hMainWindow, WM_USER, (WPARAM) L"cda://", 247 /*IPC_REFRESHPLCACHE*/);
|
||||
if (wtitle[0])
|
||||
lstrcpynA(title, AutoChar(wtitle), GETFILEINFO_TITLE_LENGTH);
|
||||
}
|
||||
g_ps_inuse = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (dev2) CDClose(&dev2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void eq_set(int on, char data[10], int preamp)
|
||||
{}
|
||||
|
||||
In_Module line =
|
||||
{
|
||||
IN_VER_RET,
|
||||
"nullsoft(in_cdda.dll)",
|
||||
0, // hMainWindow
|
||||
0, // hDllInstance
|
||||
0,
|
||||
0, // is_seekable
|
||||
1, // uses output plugins
|
||||
about,//config,
|
||||
about,
|
||||
init,
|
||||
quit,
|
||||
getfileinfo,
|
||||
infoDlg,
|
||||
isourfile,
|
||||
play,
|
||||
pause,
|
||||
unpause,
|
||||
ispaused,
|
||||
stop,
|
||||
getlength,
|
||||
getoutputtime,
|
||||
setoutputtime,
|
||||
setvolume,
|
||||
setpan,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, // dsp shit
|
||||
eq_set,
|
||||
NULL, // setinfo
|
||||
NULL // out_mod
|
||||
};
|
||||
|
||||
int m_nblock = 0;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllexport) In_Module * winampGetInModule2()
|
||||
{
|
||||
s_last_error = NULL;
|
||||
return &line;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0 // TODO?
|
||||
|
||||
__declspec(dllexport) int winampWriteExtendedFileInfo()
|
||||
{
|
||||
s_last_error = NULL;
|
||||
// write it out
|
||||
if (m_eiw_lastdrive)
|
||||
{
|
||||
AddToDatabase(&setInfo);
|
||||
m_eiw_lastdrive = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// wasabi based services for localisation support
|
||||
api_language *WASABI_API_LNG = 0;
|
||||
HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
|
||||
#ifndef IGNORE_API_GRACENOTE
|
||||
api_gracenote *AGAVE_API_GRACENOTE = 0;
|
||||
#endif
|
||||
api_application *WASABI_API_APP = 0;
|
||||
|
||||
void SetFileExtensions(void)
|
||||
{
|
||||
static char fileExtensionsString[1200] = {0}; // "CDA\0CDDA Audio Tracks (*.CDA)\0"
|
||||
char* end = 0;
|
||||
StringCchCopyExA(fileExtensionsString, 1200, "CDA", &end, 0, 0);
|
||||
StringCchCopyExA(end+1, 1200, WASABI_API_LNGSTRING(IDS_CDDA_AUDIO_TRACKS), 0, 0, 0);
|
||||
line.FileExtensions = fileExtensionsString;
|
||||
}
|
||||
|
||||
int init()
|
||||
{
|
||||
if (!IsWindow(line.hMainWindow))
|
||||
return IN_INIT_FAILURE;
|
||||
|
||||
//CoInitialize(0);
|
||||
|
||||
#ifndef IGNORE_API_GRACENOTE
|
||||
Cddb_Initialize();
|
||||
InitializeCddbCache();
|
||||
#endif
|
||||
|
||||
// loader so that we can get the localisation service api for use
|
||||
waServiceFactory *sf = line.service->service_getServiceByGuid(languageApiGUID);
|
||||
if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
|
||||
|
||||
sf = line.service->service_getServiceByGuid(AgaveConfigGUID);
|
||||
if (sf) AGAVE_API_CONFIG = reinterpret_cast<api_config*>(sf->getInterface());
|
||||
|
||||
#ifndef IGNORE_API_GRACENOTE
|
||||
sf = line.service->service_getServiceByGuid(gracenoteApiGUID);
|
||||
if (sf) AGAVE_API_GRACENOTE = reinterpret_cast<api_gracenote*>(sf->getInterface());
|
||||
#endif
|
||||
|
||||
sf = line.service->service_getServiceByGuid(applicationApiServiceGuid);
|
||||
if (sf) WASABI_API_APP = reinterpret_cast<api_application*>(sf->getInterface());
|
||||
|
||||
// need to have this initialised before we try to do anything with localisation features
|
||||
WASABI_API_START_LANG(line.hDllInstance,InCDDALangGUID);
|
||||
|
||||
static wchar_t szDescription[256];
|
||||
StringCchPrintfW(szDescription,256,WASABI_API_LNGSTRINGW(IDS_NULLSOFT_CD_PLUGIN),PLUGIN_VERSION);
|
||||
line.description = (char*)szDescription;
|
||||
|
||||
SetFileExtensions();
|
||||
|
||||
playDeviceGuard = new Nullsoft::Utility::LockGuard;
|
||||
playStatusGuard = new Nullsoft::Utility::LockGuard;
|
||||
|
||||
MainThreadId = GetCurrentThreadId();
|
||||
config_read();
|
||||
return IN_INIT_SUCCESS;
|
||||
}
|
||||
|
||||
void quit()
|
||||
{
|
||||
#ifndef IGNORE_API_GRACENOTE
|
||||
ShutdownMusicIDWorkOrder();
|
||||
#endif
|
||||
|
||||
if (playStatusGuard)
|
||||
{
|
||||
delete playStatusGuard;
|
||||
playStatusGuard = 0;
|
||||
}
|
||||
|
||||
if (windacPlayer)
|
||||
{
|
||||
delete windacPlayer;
|
||||
windacPlayer = NULL;
|
||||
}
|
||||
|
||||
if (daePlayer)
|
||||
{
|
||||
delete daePlayer;
|
||||
daePlayer = NULL;
|
||||
}
|
||||
|
||||
if (mciPlayer)
|
||||
{
|
||||
delete mciPlayer;
|
||||
mciPlayer = NULL;
|
||||
}
|
||||
|
||||
#ifndef IGNORE_API_GRACENOTE
|
||||
ShutDownCDDB();
|
||||
#endif
|
||||
|
||||
waServiceFactory *sf = line.service->service_getServiceByGuid(languageApiGUID);
|
||||
if (sf) sf->releaseInterface(WASABI_API_LNG);
|
||||
|
||||
sf = line.service->service_getServiceByGuid(AgaveConfigGUID);
|
||||
if (sf) sf->releaseInterface(AGAVE_API_CONFIG);
|
||||
|
||||
#ifndef IGNORE_API_GRACENOTE
|
||||
sf = line.service->service_getServiceByGuid(gracenoteApiGUID);
|
||||
if (sf) sf->releaseInterface(AGAVE_API_GRACENOTE);
|
||||
|
||||
Cddb_Uninitialize();
|
||||
UninitializeCddbCache();
|
||||
#endif
|
||||
|
||||
CloseTables();
|
||||
//CoUninitialize();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue