diff options
Diffstat (limited to 'Src/Plugins/Library/ml_disc')
90 files changed, 19063 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_disc/M3UWriter.cpp b/Src/Plugins/Library/ml_disc/M3UWriter.cpp new file mode 100644 index 00000000..d4ec2a13 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/M3UWriter.cpp @@ -0,0 +1,91 @@ +#include "M3UWriter.h" +#include <shlwapi.h> + +static void MakeRelativePathName( const char *filename, char *outFile, const char *path ) +{ + char outPath[ MAX_PATH ] = { 0 }; + + int common = PathCommonPrefixA( path, filename, outPath ); + if ( common && common == lstrlenA( path ) ) + { + PathAddBackslashA( outPath ); + const char *p = filename + lstrlenA( outPath ); + lstrcpyA( outFile, p ); + } + else if ( !PathIsUNCA( filename ) && PathIsSameRootA( filename, path ) ) + { + lstrcpyA( outFile, filename + 2 ); + } +} + +M3UWriter::M3UWriter() +{ + memset( basePath, 0, sizeof( basePath ) ); +} + +M3UWriter::~M3UWriter() +{ + Close(); +} + +int M3UWriter::Open( char *filename, int extendedMode ) +{ + fp = fopen( filename, "wt" ); + if ( !fp ) + return 0; + + if ( extendedMode ) + fprintf( fp, "#EXTM3U\n" ); + + extended = extendedMode; + + lstrcpynA( basePath, filename, MAX_PATH ); + PathRemoveFileSpecA( basePath ); + + return 1; +} + +int M3UWriter::Open( FILE *_fp, char *filename, int extendedMode ) +{ + fp = _fp; + if ( !fp ) + return 0; + + if ( extendedMode ) + fprintf( fp, "#EXTM3U\n" ); + + extended = extendedMode; + + lstrcpynA( basePath, filename, MAX_PATH ); + PathRemoveFileSpecA( basePath ); + + return 1; +} + +void M3UWriter::SetFilename( char *filename ) +{ + //char temp[ MAX_PATH ] = { 0 }; + //MakeRelativePathName( filename, temp, basePath ); + fprintf( fp, "%s\n", filename ); +} + +void M3UWriter::SetExtended( char *filename, char *title, int length ) +{ + if ( !extended ) + SetFilename( filename ); + else + { + //char temp[ MAX_PATH ] = { 0 }; + //MakeRelativePathName( filename, temp, basePath ); + fprintf( fp, "#EXTINF:%d,%s\n%s\n", length, title, filename ); + } +} + +void M3UWriter::Close() +{ + if ( fp != NULL ) + { + fclose( fp ); + fp = NULL; + } +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/M3UWriter.h b/Src/Plugins/Library/ml_disc/M3UWriter.h new file mode 100644 index 00000000..2f4335d5 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/M3UWriter.h @@ -0,0 +1,25 @@ +#ifndef NULLSOFT_M3UWRITERH +#define NULLSOFT_M3UWRITERH + +#include <stdio.h> +#include <windows.h> + +class M3UWriter +{ +public: + M3UWriter(); + virtual ~M3UWriter(); + + int Open(char *filename, int extendedMode); + int Open( FILE *_fp, char *filename, int extendedMode ); + void SetFilename( char *filename ); + void SetExtended( char *filename, char *title, int length ); + void Close(); + +private: + char basePath[MAX_PATH]; + int extended = 0; + FILE *fp = NULL; +}; + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/PLSWriter.cpp b/Src/Plugins/Library/ml_disc/PLSWriter.cpp new file mode 100644 index 00000000..8231d5b7 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/PLSWriter.cpp @@ -0,0 +1,65 @@ +#include "PLSWriter.h" +#include <windows.h> + +PLSWriter::PLSWriter() : numEntries(0), entryUsed(0) +{ + memset(plsFile, 0, sizeof(plsFile)); +} + +void PLSWriter::Open(char *filename) +{ + lstrcpynA(plsFile, filename, MAX_PATH); +} + +void PLSWriter::SetFilename(char *filename) +{ + char fieldbuf[32] = {0}; + BeforeSet(); + wsprintfA(fieldbuf,"File%u",numEntries); + WritePrivateProfileStringA("playlist",fieldbuf,filename,plsFile); +} + +void PLSWriter::SetTitle(char *title) +{ + char fieldbuf[32] = {0}; + BeforeSet(); + wsprintfA(fieldbuf,"Title%u",numEntries); + WritePrivateProfileStringA("playlist",fieldbuf,title,plsFile); +} + +void PLSWriter::SetLength(int length) +{ + char fieldbuf[32] = {0}; + char lenStr[32] = {0}; + BeforeSet(); + wsprintfA(fieldbuf,"Length%u",numEntries); + wsprintfA(lenStr,"%d", length); + WritePrivateProfileStringA("playlist",fieldbuf,lenStr,plsFile); +} + +void PLSWriter::BeforeSet() +{ + if (!entryUsed) + { + entryUsed=1; + numEntries++; + } +} + +void PLSWriter::Next() +{ + entryUsed=0; +} + +void PLSWriter::Close() +{ + if (numEntries) + { + char temp[32] = {0}; + wsprintfA(temp,"%u",numEntries); + WritePrivateProfileStringA("playlist","NumberOfEntries",temp,plsFile); + WritePrivateProfileStringA("playlist","Version","2",plsFile); + } + numEntries=0; + entryUsed=0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/PLSWriter.h b/Src/Plugins/Library/ml_disc/PLSWriter.h new file mode 100644 index 00000000..d97ddd47 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/PLSWriter.h @@ -0,0 +1,23 @@ +#ifndef NULLSOFT_PLSWRITERH +#define NULLSOFT_PLSWRITERH + +#include <windows.h> + +class PLSWriter +{ +public: + PLSWriter(); + void Open(char *filename); + void SetFilename(char *filename); + void SetTitle(char *title); + void SetLength(int length); + void Next(); // tells the pls writer to start writing info for the next item + void Close(); +private: + void BeforeSet(); + unsigned int numEntries; + int entryUsed; + char plsFile[MAX_PATH]; + +}; +#endif
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/ReplayGain.cpp b/Src/Plugins/Library/ml_disc/ReplayGain.cpp new file mode 100644 index 00000000..fdbd973c --- /dev/null +++ b/Src/Plugins/Library/ml_disc/ReplayGain.cpp @@ -0,0 +1,95 @@ +#include "main.h" +#include "ReplayGain.h" +#include <api/service/waservicefactory.h> +static obj_replaygain *replayGain = 0; +HANDLE rgThread = 0; +static HANDLE killSwitch = 0; +extern HWND m_extract_wnd; + +template <class api_T> +void ServiceBuild(api_T *&api_t, GUID factoryGUID_t) +{ + if (plugin.service) + { + waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t); + if (factory) + api_t = reinterpret_cast<api_T *>( factory->getInterface() ); + } +} + +template <class api_T> +void ServiceRelease(api_T *api_t, GUID factoryGUID_t) +{ + if (plugin.service && api_t) + { + waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t); + if (factory) + factory->releaseInterface(api_t); + } + api_t = NULL; +} + +DWORD WINAPI RGProc(void *data) +{ + while (WaitForSingleObjectEx(killSwitch, INFINITE, TRUE) != WAIT_OBJECT_0); + + return 0; +} + +void CreateGain() +{ + killSwitch = CreateEvent(0, FALSE, FALSE, 0); + DWORD dummy; + rgThread = CreateThread(0, 0, RGProc, 0, 0, &dummy); +} + +void CALLBACK StartGain(ULONG_PTR data) +{ + int mode = (int)data; + + ServiceBuild(replayGain, RGGUID); + if (replayGain) + replayGain->Open(mode); +} + +void CALLBACK WriteGain(ULONG_PTR data) +{ + if (replayGain) + replayGain->Write(); + + HANDLE notifyHandle =(HANDLE)data; + if (notifyHandle) + SetEvent(notifyHandle); + + PostMessage(m_extract_wnd, WM_APP+4, 0, 0); +} + +void CALLBACK CalculateGain(ULONG_PTR data) +{ + wchar_t *lastfn = (wchar_t *)data; + if (replayGain) + { + PostMessage(m_extract_wnd, WM_APP+2, 0, 0); + replayGain->ProcessTrack(lastfn); + } + free(lastfn); + PostMessage(m_extract_wnd, WM_APP+3, 0, 0); +} + +void CALLBACK CloseGain(ULONG_PTR data) +{ + if (replayGain) + { + replayGain->Close(); + ServiceRelease(replayGain, RGGUID); + replayGain = 0; + } +} + +void CALLBACK QuitThread(ULONG_PTR data) +{ + if (rgThread) + { + SetEvent(killSwitch); + } +} diff --git a/Src/Plugins/Library/ml_disc/ReplayGain.h b/Src/Plugins/Library/ml_disc/ReplayGain.h new file mode 100644 index 00000000..3e79e8c4 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/ReplayGain.h @@ -0,0 +1,16 @@ +#ifndef NULLSOFT_ML_DISC_REPLAYGAIN_H +#define NULLSOFT_ML_DISC_REPLAYGAIN_H + +#include <windows.h> +#include "../ml_rg/obj_replaygain.h" + +void CALLBACK StartGain(ULONG_PTR data); +void CALLBACK WriteGain(ULONG_PTR data); +void CALLBACK CalculateGain(ULONG_PTR data); +void CALLBACK CloseGain(ULONG_PTR data); +void CALLBACK QuitThread(ULONG_PTR data); +void CreateGain(); + +extern HANDLE rgThread; + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/api__ml_disc.h b/Src/Plugins/Library/ml_disc/api__ml_disc.h new file mode 100644 index 00000000..ac88b8ff --- /dev/null +++ b/Src/Plugins/Library/ml_disc/api__ml_disc.h @@ -0,0 +1,15 @@ +#ifndef NULLSOFT_ML_DISC_API_H +#define NULLSOFT_ML_DISC_API_H + +#include <api/service/waServiceFactory.h> + +#include <api/application/api_application.h> +#define WASABI_API_APP applicationApi + +#include "../Agave/Language/api_language.h" + +#include "../Winamp/api_stats.h" +extern api_stats *statsApi; +#define AGAVE_API_STATS statsApi + +#endif // !NULLSOFT_ML_DISC_API_H
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/banner.cpp b/Src/Plugins/Library/ml_disc/banner.cpp new file mode 100644 index 00000000..5d0b1b15 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/banner.cpp @@ -0,0 +1,222 @@ +#include "main.h" +#include ".\banner.h" +#include "..\gen_ml\graphics.h" + + +MLBanner::MLBanner(void) +{ + bmpBck = NULL; + bmpLogo = NULL; + bmpLogoMask = NULL; + bmpBanner = NULL; + m_hwnd = NULL; + oldWndProc = NULL; + + color1 = RGB(0,0,0); + color2 = RGB(255,255,255); + + hInstance = NULL; + logoResId = 0; + bgndResId = 0; + + SetRect(&rcBanner, 0,0,0,0); +} +MLBanner::~MLBanner(void) +{ + DestroyImages(); + SetWindowLong(m_hwnd, GWL_WNDPROC, (LONG)oldWndProc); + oldWndProc = NULL; +} + +void MLBanner::SetColors(int color1, int color2) +{ + this->color1 = color1; + this->color2 = color2; + ReloadImages(); +} + +void MLBanner::SetImages(HINSTANCE hInstance, int bgndResId, int logoResId) +{ + this->hInstance = hInstance; + this->logoResId = logoResId; + this->bgndResId = bgndResId; + ReloadImages(); +} + +void MLBanner::ReloadImages(void) +{ + DestroyImages(); + if (hInstance) + { + if (bgndResId) + { + bmpBck = (HBITMAP)LoadImage(hInstance, MAKEINTRESOURCE(bgndResId), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); + if (bmpBck) bmpBck = PatchBitmapColors24(bmpBck, color1, color2, Filter1); + } + if (logoResId) + { + bmpLogo = (HBITMAP)LoadImage(hInstance, MAKEINTRESOURCE(logoResId), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); + if (bmpLogo) + { + bmpLogoMask = CreateBitmapMask(bmpLogo, 1,1); + } + } + } + +} + +void MLBanner::DestroyImages(void) +{ + if (bmpBck) DeleteObject(bmpBck); + bmpBck = NULL; + + if (bmpLogo) DeleteObject(bmpLogo); + bmpLogo = NULL; + + if (bmpLogoMask) DeleteObject(bmpLogoMask); + bmpLogoMask = NULL; + + if (bmpBanner) DeleteObject(bmpBanner); + bmpBanner = NULL; +} + + + +void MLBanner::UpdateBunnerBmp(void) +{ + if (bmpBanner) DeleteObject(bmpBanner); + + HDC hdc = GetDC(m_hwnd); + + bmpBanner = CreateCompatibleBitmap(hdc, rcBanner.right, rcBanner.bottom); + HDC memDstDC = CreateCompatibleDC (hdc); + HDC memSrcDC = CreateCompatibleDC (hdc); + HBITMAP obmp1 = (HBITMAP)SelectObject(memDstDC, bmpBanner); + HBITMAP obmp2 = (HBITMAP)SelectObject(memSrcDC, bmpBck); + + for (int i = 0; i < rcBanner.right; i++) + { + BitBlt(memDstDC, + i,0, + 1, rcBanner.bottom, + memSrcDC, + 0,0, + SRCCOPY); + + } + + BITMAP bm; + GetObject(bmpLogo, sizeof(BITMAP), &bm); + + SelectObject(memSrcDC, bmpLogoMask); + BitBlt(memDstDC, + 6, + max(2, (rcBanner.bottom - bm.bmHeight) / 2), + min(rcBanner.right - 4, bm.bmWidth), + min(rcBanner.bottom - 2, bm.bmHeight), + memSrcDC, + 0,0, + SRCAND); + + SelectObject(memSrcDC, bmpLogo); + BitBlt(memDstDC, + 6, + max(2, (rcBanner.bottom - bm.bmHeight) / 2), + min(rcBanner.right - 4, bm.bmWidth), + min(rcBanner.bottom - 2, bm.bmHeight), + memSrcDC, + 0,0, + SRCPAINT); + + ReleaseDC(m_hwnd, hdc); + + SelectObject(memDstDC, obmp1); + SelectObject(memSrcDC, obmp2); + + DeleteDC(memDstDC); + DeleteDC(memSrcDC); + +} + +void MLBanner::Init(HWND hwnd) +{ + m_hwnd = hwnd; + SetWindowLong(hwnd,GWL_USERDATA,(LONG)this); + oldWndProc= (WNDPROC) SetWindowLong(hwnd, GWL_WNDPROC, (LONG)newWndProc); + UpdateBunnerBmp(); +} + +BOOL CALLBACK MLBanner::newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + MLBanner *banner = (MLBanner*)GetWindowLong(hwndDlg, GWL_USERDATA); + + switch(uMsg) + { + case WM_SIZE: + if (SIZE_MINIMIZED != wParam) + { + SetRect(&banner->rcBanner, 0,0,LOWORD(lParam),HIWORD(lParam)); + banner->UpdateBunnerBmp(); + } + break; + case WM_ERASEBKGND: + { + HDC hdc = GetDC(hwndDlg); + if (banner->bmpBanner) + { + HDC memSrcDC = CreateCompatibleDC (hdc); + HBITMAP obmp = (HBITMAP)SelectObject(memSrcDC, banner->bmpBanner); + StretchBlt( hdc, + banner->rcBanner.left, + banner->rcBanner.top, + banner->rcBanner.right - banner->rcBanner.left, + banner->rcBanner.bottom - banner->rcBanner.top, + memSrcDC, + banner->rcBanner.left, + banner->rcBanner.top, + banner->rcBanner.right - banner->rcBanner.left, + banner->rcBanner.bottom - banner->rcBanner.top, + SRCCOPY); + SelectObject(memSrcDC, obmp); + DeleteDC(memSrcDC); + } + ReleaseDC(hwndDlg, hdc); + } + return TRUE; + case WM_PAINT: + { + PAINTSTRUCT pt; + HDC hdc = BeginPaint(hwndDlg, &pt); + if (!banner->bmpBanner) + { + SetRect(&banner->rcBanner, 0,0,pt.rcPaint.right - pt.rcPaint.left, pt.rcPaint.bottom - pt.rcPaint.top); + banner->UpdateBunnerBmp(); + } + if (banner->bmpBanner) + { + HDC memSrcDC = CreateCompatibleDC (hdc); + HBITMAP obmp = (HBITMAP)SelectObject(memSrcDC, banner->bmpBanner); + StretchBlt( hdc, + pt.rcPaint.left, + pt.rcPaint.top, + pt.rcPaint.right - pt.rcPaint.left, + pt.rcPaint.bottom - pt.rcPaint.top, + memSrcDC, + pt.rcPaint.left, + pt.rcPaint.top, + pt.rcPaint.right - pt.rcPaint.left, + pt.rcPaint.bottom - pt.rcPaint.top, + SRCCOPY); + SelectObject(memSrcDC, obmp); + DeleteDC(memSrcDC); + ValidateRect(hwndDlg, &pt.rcPaint); + } + EndPaint(hwndDlg, &pt); + } + break; + } + + return CallWindowProc(banner->oldWndProc, hwndDlg, uMsg, wParam, lParam); +} + +
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/banner.h b/Src/Plugins/Library/ml_disc/banner.h new file mode 100644 index 00000000..9b7409cf --- /dev/null +++ b/Src/Plugins/Library/ml_disc/banner.h @@ -0,0 +1,44 @@ +#ifndef NULLSOFT_ML_BANNER_HEADER +#define NULLSOFT_ML_BANNER_HEADER + +#include <windows.h> + +class MLBanner +{ +public: + MLBanner(void); + ~MLBanner(void); + +public: + + void SetColors(int color1, int color2); + void SetImages(HINSTANCE hInstance, int bgndResId, int logoResId); + void Init(HWND hwnd); + void ReloadImages(void); + +protected: + void DestroyImages(void); + void UpdateBunnerBmp(void); + static BOOL CALLBACK newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); + +private: + + HWND m_hwnd; + HBITMAP bmpBck; + HBITMAP bmpLogo; + HBITMAP bmpLogoMask; + HBITMAP bmpBanner; + + WNDPROC oldWndProc; + + HINSTANCE hInstance; + int logoResId; + int bgndResId; + + int color1; + int color2; + + RECT rcBanner; +}; + +#endif // NULLSOFT_ML_BANNER_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/cdburn.cpp b/Src/Plugins/Library/ml_disc/cdburn.cpp new file mode 100644 index 00000000..6f05d06a --- /dev/null +++ b/Src/Plugins/Library/ml_disc/cdburn.cpp @@ -0,0 +1,2155 @@ +#include "main.h" +#include <stdio.h> +#include "../nu/ns_wc.h" +#include "resource.h" +#include "../nu/listview.h" +#include "../nu/DialogSkinner.h" +#include "../nu/ChildSizer.h" +#include "config.h" +#include "../../General/gen_ml/gaystring.h" +#include "../Winamp/burn.h" +#include "../Winamp/strutil.h" +#include <std::vector> +#include "../nu/AutoChar.h" +#include "../nu/AutoWide.h" +#include <api/service/waServiceFactory.h> +#include "../playlist/ifc_playlistloadercallback.h" +#include "../playlist/api_playlistmanager.h" +#include <imapi.h> +#include <imapierror.h> +#include <shlwapi.h> +#include <strsafe.h> + +//shit to finish: +//-erase CDRWs +//-cache the veritas handle +//-recurse add folders +//-check for available space on HD before burning +//-the resampling in convert + + +#define WM_EX_OPCOMPLETED (WM_USER + 0x100) + +class PLCallBack : ifc_playlistloadercallback +{ +public: + PLCallBack(void) : fileList(0) {}; + ~PLCallBack(void) {}; +public: + void OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info) + { + fileList->push_back(new GayString(AutoChar(filename))); + } + RECVS_DISPATCH; +public: + std::vector<GayString*> *fileList; +}; + +#define CBCLASS PLCallBack +START_DISPATCH; +VCB(IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile) +END_DISPATCH; +#undef CBCLASS + +class PLCallBackW : ifc_playlistloadercallback +{ +public: + PLCallBackW(void) : fileList(0) {}; + ~PLCallBackW(void) {}; +public: + void OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info) + { + fileList->push_back(new GayStringW(filename)); + } + RECVS_DISPATCH; +public: + std::vector<GayStringW*> *fileList; +}; + +#define CBCLASS PLCallBackW +START_DISPATCH; +VCB(IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile) +END_DISPATCH; +#undef CBCLASS + +static INT_PTR WINAPI DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#include "../burnlib/burnlib.h" + +static W_ListView m_statuslist; + +static HWND m_hwndstatus; +static char m_cdrom; +static int m_is_cdrw, m_availsecs; +static int m_max_speed; +static int m_dragging, m_drag_item; +static HWND prevWnd = NULL; +itemRecordListW itemCache[100] = {0}; +static int percentCompleted = 0; +static DWORD pidBurner = 0; + +static HFONT hPLFont = NULL; + +static int LETTERTOINDEX(char c) +{ + c = (char)toupper(c); + if (c < 'A') c = 'A'; + if (c > 'Z') c = 'Z'; + return c -'A'; +} + +#include "../winamp/wa_ipc.h" + + +#define TIMER_NOTIFYINFO_ID 1985 +#define TIMER_NOTIFYINFO_DELAY 200 + + +static ChildWndResizeItem burnwnd_rlist[] = +{ + {IDC_LIST2, 0x0011}, + {IDC_CDINFO, 0x0010}, + {IDC_ADD, 0x0101}, + {IDC_BURN, 0x0101}, + {IDC_CLEAR, 0x0101}, + {IDC_BURN_OPTS, 0x0101}, + {IDC_CANCEL_BURN, 0x0101}, + {IDC_LOGO, 0x1010}, + {IDC_BTN_SHOWINFO, 0x1111}, +}; +static _inline void code(long* v, long* k) +{ + unsigned long y = v[0], z = v[1], sum = 0, /* set up */ + delta = 0x9e3779b9, n = 32 ; /* key schedule constant*/ + + while (n-- > 0) + { /* basic cycle start */ + sum += delta; + y += ((z << 4) + k[0]) ^(z + sum) ^((z >> 5) + k[1]); + z += ((y << 4) + k[2]) ^(y + sum) ^((y >> 5) + k[3]); /* end cycle */ + } + v[0] = y; v[1] = z; + +} + +static void startBurn(HWND hwndDlg, char driveletter) +{ + g_config->WriteInt(L"cdburnmaxspeed", m_max_speed); + + //write the temp playlist to disk + FILE *fp; + char filename[MAX_PATH] = {0}, tp[MAX_PATH] = {0}; + + pidBurner = 0; + + if (!GetTempPathA(sizeof(tp), tp)) lstrcpynA(tp, ".", MAX_PATH); + if (GetTempFileNameA(tp, "BRN", 0, filename)) + { + unlink(filename); + StringCchCatA(filename, MAX_PATH, ".m3u8"); + } + else lstrcpynA(filename, "brn_tmp.m3u8", MAX_PATH); + + fp = fopen(filename, "wt"); + if (!fp) + { + wchar_t title[16] = {0}; + MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_ERROR_WRITING_TEMP_BURN_LIST), + WASABI_API_LNGSTRINGW_BUF(IDS_ERROR,title,16), MB_OK); + return ; + } + int idx = LETTERTOINDEX(driveletter); + fprintf(fp, "#EXTM3U\n"); + for (int i = 0;i < itemCache[idx].Size;i++) + { + fprintf(fp, "#EXTINF:%d,%s\n", itemCache[idx].Items[i].length, (char *)AutoChar(itemCache[idx].Items[i].title, CP_UTF8)); + fprintf(fp, "%s\n", (char *)AutoChar(itemCache[idx].Items[i].filename, CP_UTF8)); + } + fclose(fp); + + burnCDStruct bcds = + { + m_cdrom, + filename, + hwndDlg, + "", + }; + pidBurner = (DWORD)(INT_PTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM) & bcds, IPC_BURN_CD); + if (!pidBurner) + { + wchar_t title[16] = {0}; + unlink(filename); + MessageBox(hwndDlg, AutoWide(bcds.error), WASABI_API_LNGSTRINGW_BUF(IDS_ERROR,title,16), MB_OK); + } +} + +static void link_handledraw(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (uMsg == WM_DRAWITEM) + { + DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT *)lParam; + if (di->CtlType == ODT_BUTTON) + { + wchar_t wt[123] = {0}; + int y; + RECT r; + HPEN hPen, hOldPen; + GetDlgItemText(hwndDlg, (int)wParam, wt, 123); + + // draw text + SetTextColor(di->hDC, (di->itemState & ODS_SELECTED) ? RGB(220, 0, 0) : RGB(0, 0, 220)); + r = di->rcItem; + r.left += 2; + DrawText(di->hDC, wt, -1, &r, DT_VCENTER | DT_SINGLELINE); + + memset(&r, 0, sizeof(r)); + DrawText(di->hDC, wt, -1, &r, DT_SINGLELINE | DT_CALCRECT); + + // draw underline + y = di->rcItem.bottom - ((di->rcItem.bottom - di->rcItem.top) - (r.bottom - r.top)) / 2 - 1; + hPen = CreatePen(PS_SOLID, 0, (di->itemState & ODS_SELECTED) ? RGB(220, 0, 0) : RGB(0, 0, 220)); + hOldPen = (HPEN) SelectObject(di->hDC, hPen); + MoveToEx(di->hDC, di->rcItem.left + 2, y, NULL); + LineTo(di->hDC, di->rcItem.right + 2 - ((di->rcItem.right - di->rcItem.left) - (r.right - r.left)), y); + SelectObject(di->hDC, hOldPen); + DeleteObject(hPen); + + } + } +} + +static void refreshList() +{ + if (!m_hwndstatus) return ; + + ListView_SetItemCount(m_statuslist.getwnd(), 0); + int idx = LETTERTOINDEX(m_cdrom); + ListView_SetItemCount(m_statuslist.getwnd(), itemCache[idx].Size); + if (itemCache[idx].Size > 0) ListView_RedrawItems(m_statuslist.getwnd(), 0, itemCache[idx].Size - 1); +} +static int m_last_trackpos; + + +typedef struct _MEDIAINFO +{ + CHAR cLetter; + BOOL bInserted; + BOOL bRecordable; + BOOL bRewritable; + BOOL bBlank; + ULONG nSectorsFree; + ULONG nSectorsUsed; +} MEDIAINFO; + +static HRESULT GetMediaInfoFromSonic(MEDIAINFO *pmi) +{ + HRESULT hr; + + hr = S_OK; + + char name[]= "cda://X.cda"; + char buf2[64] = ""; + char buf3[64] = ""; + + name[6] = pmi->cLetter; + + pmi->bInserted = FALSE; + pmi->bRewritable = FALSE; + pmi->nSectorsFree = 0; + pmi->nSectorsUsed = 0; + + pmi->bRecordable = TRUE; + getFileInfo(name, "cdtype", buf3, sizeof(buf3)); + if (buf3[0] && 0 == lstrcmpA(buf3, "CDRW")) pmi->bRewritable = TRUE; + + getFileInfo(name, "cdlengths", buf2, sizeof(buf2)); + if (buf2[0]) + { + pmi->bInserted = TRUE; + pmi->nSectorsFree = atoi(buf2); + } + + return hr; +} + +static void CALLBACK FreeAsyncParam(DM_NOTIFY_PARAM *phdr) +{ + switch(phdr->opCode) + { + case DMOP_IMAPIINFO: + break; + } + free(phdr); +} +static void FinishSetStatus(HWND hwndDlg, MEDIAINFO *pmi) +{ + int freesecs; + if(pmi->bInserted) + { + freesecs = (pmi->nSectorsFree * 2048) / (150 * 1024); //150kb/s as its considered DATA CD at this point in veritas + } + else + { + freesecs = 74 * 60; //Default to 74mns CDR + } + + m_availsecs = freesecs; + + int idx = LETTERTOINDEX(m_cdrom); + int usedlen = 0; + int truncpos = 0; + for (int i = 0;i < itemCache[idx].Size;i++) + { + usedlen += itemCache[idx].Items[i].length; + if (usedlen > m_availsecs) + truncpos++; + } + m_availsecs -= usedlen; + + wchar_t status[256] = {0}; + if (!pmi->bInserted) + WASABI_API_LNGSTRINGW_BUF(IDS_NO_BLANK_CDR_IN_DRIVE,status,512); + else + { + StringCchPrintf(status, 512, WASABI_API_LNGSTRINGW(IDS_X_CAPACITY_DETAILS), + (pmi->bRewritable) ? L"CD-RW" : L"CD-R" , freesecs / 60, freesecs % 60); + } + + wchar_t temp[16] = {0}; + StringCchPrintf(status + wcslen(status), 256, + WASABI_API_LNGSTRINGW(IDS_USED_X_X_TRACKS), + usedlen / 60, + usedlen % 60, + itemCache[idx].Size, + WASABI_API_LNGSTRINGW_BUF(itemCache[idx].Size == 1 ? IDS_TRACK : IDS_TRACKS,temp,16)); + + if (freesecs && pmi->bInserted) + { + if (m_availsecs >= 0) StringCchPrintf(status + wcslen(status), 256, WASABI_API_LNGSTRINGW(IDS_AVAILABLE_X_X), + m_availsecs / 60, m_availsecs % 60); + else StringCchPrintf(status + wcslen(status), 256, WASABI_API_LNGSTRINGW(IDS_X_OVER_CAPACITY_REMOVE_X_TRACKS), + -m_availsecs / 60, -m_availsecs % 60, truncpos); + } + SetDlgItemText(hwndDlg, IDC_CDINFO, status); + m_last_trackpos = -1; + + m_is_cdrw = pmi->bRewritable; + ListView_RedrawItems(m_statuslist.getwnd(), 0, itemCache[idx].Size - 1); +} + +static void SetStatus(HWND hwndDlg, CHAR cLetter) +{ + if (DM_MODE_BURNING == DriveManager_GetDriveMode(cLetter) && + NULL != (m_burning_other_wnd = cdburn_FindBurningHWND(cLetter))) + { + prevWnd = (HWND)SendMessage(m_burning_other_wnd, WM_BURNUPDATEOWNER, 0, (LPARAM)hwndDlg); + if (prevWnd == hwndDlg) prevWnd = NULL; + DWORD state = (DWORD)(INT_PTR)SendMessage(m_burning_other_wnd, WM_BURNGETSTATUS, BURNSTATUS_STATE, 0); + if (state) + { + SetDlgItemText(hwndDlg, IDC_CDINFO, WASABI_API_LNGSTRINGW(IDS_BURNING)); + ShowWindow(GetDlgItem(hwndDlg, IDC_CLEAR), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_BURN), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_BURN_OPTS), SW_SHOWNA); + ShowWindow(GetDlgItem(hwndDlg, IDC_CANCEL_BURN), SW_SHOWNA); + SetDlgItemText(hwndDlg, IDC_CANCEL_BURN, WASABI_API_LNGSTRINGW(IDS_CANCEL_BURN)); + m_availsecs = 0; + m_last_trackpos = -1; + m_is_cdrw = 0; + percentCompleted = 0; + UpdateWindow(hwndDlg); + } + + SendMessage(hwndDlg, WM_BURNNOTIFY, BURN_STATECHANGED, state); + ShowWindow(m_burning_other_wnd, g_config->ReadInt(L"cdburnstatuswnd", 1) ? SW_SHOWNA : SW_HIDE); + PostMessage(m_burning_other_wnd, WM_BURNCONFIGCHANGED, BURNCFG_HIDEVIEW, !g_config->ReadInt(L"cdburnstatuswnd", 1)); + PostMessage(m_burning_other_wnd, WM_BURNCONFIGCHANGED, BURNCFG_AUTOEJECT, g_config->ReadInt(L"cdburnautoeject", 1)); + PostMessage(m_burning_other_wnd, WM_BURNCONFIGCHANGED, BURNCFG_ADDTODB, g_config->ReadInt(L"cdburnautoadddb", 0)); + PostMessage(m_burning_other_wnd, WM_BURNCONFIGCHANGED, BURNCFG_AUTOCLOSE, g_config->ReadInt(L"cdburnautoclose", 0)); + } + else + { + BOOL br; + ShowWindow(GetDlgItem(hwndDlg, IDC_CLEAR), SW_SHOWNA); + ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_SHOWNA); + ShowWindow(GetDlgItem(hwndDlg, IDC_BURN), SW_SHOWNA); + ShowWindow(GetDlgItem(hwndDlg, IDC_BURN_OPTS), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_CANCEL_BURN), SW_HIDE); + + SetDlgItemText(hwndDlg, IDC_CDINFO, WASABI_API_LNGSTRINGW(IDS_CALCULATING)); + + UpdateWindow(hwndDlg); + + DM_IMAPI_PARAM *pIMAPI = (DM_IMAPI_PARAM*)calloc(1, sizeof(DM_IMAPI_PARAM)); + if (pIMAPI) + { + pIMAPI->header.cLetter = cLetter; + pIMAPI->header.callback = (INT_PTR)hwndDlg; + pIMAPI->header.uMsg = WM_EX_OPCOMPLETED; + pIMAPI->header.fnFree = FreeAsyncParam; + pIMAPI->header.fFlags = DMF_QUERYMEDIATYPE | DMF_QUERYMEDIAINFO; + br = DriveManager_GetIMAPIInfo(pIMAPI); + } + else br = FALSE; + if (!br) SetDlgItemText(hwndDlg, IDC_CDINFO, WASABI_API_LNGSTRINGW(IDS_DISC_READ_ERROR)); + } +} + +static void deleteSelectedItems(HWND hwndDlg, CHAR cLetter) +{ + int idx = LETTERTOINDEX(cLetter); + for (int i = itemCache[idx].Size - 1;i >= 0;i--) + { + if (m_statuslist.GetSelected(i)) + { + freeRecord(&itemCache[idx].Items[i]); + int l = itemCache[idx].Size - i - 1; + if (l > 0) memcpy(&itemCache[idx].Items[i], &itemCache[idx].Items[i + 1], sizeof(itemRecordW)*l); + itemCache[idx].Size--; + } + } + SetStatus(hwndDlg, cLetter); + refreshList(); +} + +static void selectAll() +{ + int l = m_statuslist.GetCount(); + for (int i = 0;i < l;i++) m_statuslist.SetSelected(i); +} + +static void playSelectedItems(HWND hwndDlg, int enqueue) +{ + int idx = LETTERTOINDEX(m_cdrom); + if (!enqueue) SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_DELETE); + + for (int i = 0;i < itemCache[idx].Size;i++) + { + if (!m_statuslist.GetSelected(i)) continue; + + //send the file to winamp + COPYDATASTRUCT cds; + cds.dwData = IPC_PLAYFILEW; + cds.lpData = (void *)itemCache[idx].Items[i].filename; + cds.cbData = (DWORD)(sizeof(wchar_t *) * (wcslen(itemCache[idx].Items[i].filename) + 1)); // include space for null char + SendMessageW(plugin.hwndWinampParent, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds); + } + + if (!enqueue) SendMessageW(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_STARTPLAY); +} +BOOL CALLBACK CantBurnProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + wchar_t *message = (wchar_t *)lParam; + + // due to quirks with the more common resource editors, is easier to just store the string + // internally only with \n and post-process to be \r\n (as here) so it will appear correctly + // on new lines as is wanted (silly multiline edit controls) + wchar_t tmp2[1024] = {0}, *t2 = tmp2; + while(message && *message && (t2 - tmp2 < 1024)) + { + if(*message == L'\n') + { + *t2 = L'\r'; + t2 = CharNextW(t2); + } + *t2 = *message; + message = CharNextW(message); + t2 = CharNextW(t2); + } + + SetDlgItemText(hwnd, IDC_MESSAGE2, tmp2); + } + return 0; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + EndDialog(hwnd, 0); + break; + case IDCANCEL: + EndDialog(hwnd, -1); + break; + } + } + return 0; +} + +HRESULT ResolveShortCut(HWND hwnd, LPCSTR pszShortcutFile, LPSTR pszPath) +{ + HRESULT hres; + IShellLinkA* psl; + WIN32_FIND_DATAA wfd; + + *pszPath = 0; // assume failure + + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + IID_IShellLinkA, (void **) & psl); + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + + hres = psl->QueryInterface(IID_IPersistFile, (void **) & ppf); // OLE 2! Yay! --YO + if (SUCCEEDED(hres)) + { + wchar_t wsz[MAX_PATH] = {0}; + MultiByteToWideCharSZ(CP_ACP, 0, pszShortcutFile, -1, wsz, MAX_PATH); + + hres = ppf->Load(wsz, STGM_READ); + if (SUCCEEDED(hres)) + { + hres = psl->Resolve(hwnd, SLR_ANY_MATCH); + if (SUCCEEDED(hres)) + { + char szGotPath[MAX_PATH] = {0}; + lstrcpynA(szGotPath, pszShortcutFile, MAX_PATH); + hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATAA *) & wfd, + SLGP_SHORTPATH); + lstrcpynA(pszPath, szGotPath, MAX_PATH); + } + } + ppf->Release(); + } + psl->Release(); + } + return SUCCEEDED(hres); +} + +HRESULT ResolveShortCut(HWND hwnd, LPCWSTR pszShortcutFile, LPWSTR pszPath) +{ + HRESULT hres; + IShellLinkW* psl; + WIN32_FIND_DATAW wfd; + + *pszPath = 0; // assume failure + + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + IID_IShellLinkW, (void **) & psl); + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + + hres = psl->QueryInterface(IID_IPersistFile, (void **) & ppf); // OLE 2! Yay! --YO + if (SUCCEEDED(hres)) + { + /*wchar_t wsz[MAX_PATH] = {0}; + MultiByteToWideCharSZ(CP_ACP, 0, pszShortcutFile, -1, wsz, MAX_PATH);*/ + + hres = ppf->Load(pszShortcutFile/*wsz*/, STGM_READ); + if (SUCCEEDED(hres)) + { + hres = psl->Resolve(hwnd, SLR_ANY_MATCH); + if (SUCCEEDED(hres)) + { + wchar_t szGotPath[MAX_PATH] = {0}; + wcsncpy(szGotPath, pszShortcutFile, MAX_PATH); + hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATAW *) & wfd, + SLGP_SHORTPATH); + wcsncpy(pszPath, szGotPath, MAX_PATH); + } + } + ppf->Release(); + } + psl->Release(); + } + return SUCCEEDED(hres); +} + +static int checkFile(const char *file) +{ + //check if the file is supported by winamp + const char *ext = extension(file); + if (!ext || !ext[0]) return 0; + if (strstr(file, "://") && !strstr(file, "cda://")) return 0; + +#if 0 // benski> this would be neat to have, but will fail with unicode filenames (which in_mp3 can open anyway)... TODO: make it workable later + HANDLE hFile = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == hFile && GetLastError() != ERROR_FILE_NOT_FOUND) + { + wchar_t message[1024] = {0}; + StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_FILE_X_CANNOT_BE_BURNED_REASON_NOT_FOUND), AutoWide(file), AutoWide(ext)); + return WASABI_API_DIALOGBOXPARAM(IDD_NOBURN, g_hwnd, CantBurnProc, (LPARAM)message); + } + CloseHandle(hFile); +#endif + + char *m_extlist = (char*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GET_EXTLIST); + { + int found = 0; + char *a = m_extlist; + while (a && *a) + { + if (!lstrcmpiA(a, ext)) + { + found = 1; + break; + } + a += lstrlenA(a) + 1; + } + GlobalFree((HGLOBAL)m_extlist); + if (!found) + { + wchar_t message[1024] = {0}; + StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_FILE_X_CANNOT_BE_BURNED_REASON_FILETYPE_NOT_REGISTERED), AutoWide(file), AutoWide(ext)); + return (int)(INT_PTR)WASABI_API_DIALOGBOXPARAM(IDD_NOBURN, plugin.hwndLibraryParent, CantBurnProc, (LPARAM)message); + } + } + + //check for type + char tmp[64] = {0, }; + getFileInfo(file, "type", tmp, sizeof(tmp) - 1); + if (tmp[0] && tmp[0] != '0') + { + wchar_t message[1024], temp[128] = {0}; + StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_FILE_X_CANNOT_BE_BURNED_REASON_X),AutoWide(file), + WASABI_API_LNGSTRINGW_BUF((tmp[0] == '1' ? IDS_VIDEO_FILES_CANNOT_BE_BURNED : IDS_NOT_AN_AUDIO_FILE),temp,128)); + return (int)(INT_PTR)WASABI_API_DIALOGBOXPARAM(IDD_NOBURN, plugin.hwndLibraryParent, CantBurnProc, (LPARAM)message); + + } + + // note: this check is NOT meant as any sort of protection.. It simply saves the user the hassle of an error later + if (getFileInfo(file, "burnable", tmp, 64) // most plugins don't support this extended file info, so failure is OK + && tmp[0] == '0') // if it does support it, then we can check whether or not it's burnable + { + wchar_t message[1024] = {0}; + StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_FILE_CANNOT_BE_BURNED), AutoWide(file)); + if (getFileInfo(file, "noburnreason", tmp, 64)) + { + StringCchPrintfW(message, 1024, + WASABI_API_LNGSTRINGW(IDS_FILE_X_CANNOT_BE_BURNED_REASON_X), + AutoWide(file), AutoWide(tmp)); + } + return (int)(INT_PTR)WASABI_API_DIALOGBOXPARAM(IDD_NOBURN, plugin.hwndLibraryParent, CantBurnProc, (LPARAM)message); + } + + return 1; +} + + +static int checkFile(const wchar_t *file) +{ + //check if the file is supported by winamp + const wchar_t *ext = PathFindExtension(file); + if (!ext || !ext[0]) return 0; + ext++; + if (wcsstr(file, L"://") && !wcsstr(file, L"cda://")) return 0; + +#if 0 // benski> this would be neat to have, but will fail with unicode filenames (which in_mp3 can open anyway)... TODO: make it workable later + HANDLE hFile = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == hFile && GetLastError() == ERROR_FILE_NOT_FOUND) + { + wchar_t message[1024] = {0}; + StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_FILE_X_CANNOT_BE_BURNED_REASON_NOT_FOUND), file, ext); + return WASABI_API_DIALOGBOXPARAM(IDD_NOBURN, g_hwnd, CantBurnProc, (LPARAM)message); + } + CloseHandle(hFile); +#endif + wchar_t *m_extlist = (wchar_t*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GET_EXTLISTW); + { + int found = 0; + wchar_t *a = m_extlist; + while (a && *a) + { + if (!lstrcmpiW(a, ext)) + { + found = 1; + break; + } + a += lstrlenW(a) + 1; + } + GlobalFree((HGLOBAL)m_extlist); + if (!found) + { + wchar_t message[1024] = {0}; + StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_FILE_X_CANNOT_BE_BURNED_REASON_FILETYPE_NOT_REGISTERED), file, ext); + return (int)(INT_PTR)WASABI_API_DIALOGBOXPARAM(IDD_NOBURN, plugin.hwndLibraryParent, CantBurnProc, (LPARAM)message); + } + } + + //check for type + wchar_t tmp[64] = {0, }; + getFileInfoW(file, L"type", tmp, 64); + if (tmp[0] && tmp[0] != '0') + { + wchar_t message[1024] = {0}, temp[128] = {0}; + StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_FILE_X_CANNOT_BE_BURNED_REASON_X), file, + WASABI_API_LNGSTRINGW_BUF((tmp[0] == '1' ? IDS_VIDEO_FILES_CANNOT_BE_BURNED : IDS_NOT_AN_AUDIO_FILE),temp,128)); + return (int)(INT_PTR)WASABI_API_DIALOGBOXPARAM(IDD_NOBURN, plugin.hwndLibraryParent, CantBurnProc, (LPARAM)message); + + } + + // note: this check is NOT meant as any sort of protection.. It simply saves the user the hassle of an error later + if (getFileInfoW(file, L"burnable", tmp, 64) // most plugins don't support this extended file info, so failure is OK + && tmp[0] == '0') // if it does support it, then we can check whether or not it's burnable + { + wchar_t message[1024] = {0}; + StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_FILE_CANNOT_BE_BURNED), file); + if (getFileInfoW(file, L"noburnreason", tmp, 64)) + { + StringCchPrintfW(message, 1024, + WASABI_API_LNGSTRINGW(IDS_FILE_X_CANNOT_BE_BURNED_REASON_X), + file, tmp); + } + return (int)(INT_PTR)WASABI_API_DIALOGBOXPARAM(IDD_NOBURN, plugin.hwndLibraryParent, CantBurnProc, (LPARAM)message); + } + + return 1; +} + + +void cdburn_clearBurner(char driveletter) +{ + emptyRecordList(&itemCache[LETTERTOINDEX(driveletter)]); +} +void cdburn_addfile(char* file, std::vector<GayString*> *files, api_playlistmanager* plManager, ifc_playlistloadercallback *plCB); +void cdburn_addfile(wchar_t* file, std::vector<GayStringW*> *files, api_playlistmanager* plManager, ifc_playlistloadercallback *plCB); +void cdburn_addfolder(const char* folder, std::vector<GayString*> *files, api_playlistmanager* plManager, ifc_playlistloadercallback *plCB); +void cdburn_addfolder(const wchar_t* folder, std::vector<GayStringW*> *files, api_playlistmanager* plManager, ifc_playlistloadercallback *plCB); + +void cdburn_appendFile(char *file, char cLetter) +{ + std::vector<GayString*> files; + waServiceFactory *plmFactory = plugin.service->service_getServiceByGuid(api_playlistmanagerGUID); + api_playlistmanager *plManager = (plmFactory) ? (api_playlistmanager*)plmFactory->getInterface() : NULL; + + int idx = LETTERTOINDEX(cLetter); + int validFile = 1; + + if (itemCache[idx].Size > 255) return; + itemRecordListW newItems = {0, 0, 0}; + PLCallBack plCB; + plCB.fileList = &files; + + cdburn_addfile(file, &files, (api_playlistmanager*)plManager, (ifc_playlistloadercallback*)&plCB); + + size_t x; + + for (x = 0; x < files.size(); x ++) // temp record . replace it !!! + { + char *fn = files.at(x)->Get(); + + validFile = checkFile(fn); + // can't use switch here cause break won't work + if (validFile == -1) // bad file and user cancelled + break; + if (validFile) // bad file, user skipped + { + allocRecordList(&newItems, newItems.Size + 1); + if (!newItems.Alloc) break; + + char title[2048] = {0}; + basicFileInfoStruct bfis = {fn, 0, 0, title, sizeof(title) - 1,}; + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&bfis, IPC_GET_BASIC_FILE_INFO); + if (bfis.length > 0) + { + memset((void *)&(newItems.Items[newItems.Size]), 0, sizeof(itemRecordW)); + newItems.Items[newItems.Size].filename = AutoWideDup(fn); + newItems.Items[newItems.Size].title = AutoWideDup(title); + newItems.Items[newItems.Size].length = bfis.length; + newItems.Size++; + } + } + delete(files.at(x)->Get()); + } + + if (validFile != -1) + copyRecordList(&itemCache[idx], &newItems); + refreshList(); + if (m_hwndstatus) SetStatus(m_hwndstatus, cLetter); + if (plManager) plmFactory->releaseInterface(plManager); +} + +void cdburn_appendFile(wchar_t *file, char cLetter) +{ + std::vector<GayStringW*> files; + waServiceFactory *plmFactory = plugin.service->service_getServiceByGuid(api_playlistmanagerGUID); + api_playlistmanager *plManager = (plmFactory) ? (api_playlistmanager*)plmFactory->getInterface() : NULL; + + int idx = LETTERTOINDEX(cLetter); + int validFile = 1; + + if (itemCache[idx].Size > 255) return; + itemRecordListW newItems = {0, 0, 0}; + PLCallBackW plCB; + plCB.fileList = &files; + + cdburn_addfile(file, &files, (api_playlistmanager*)plManager, (ifc_playlistloadercallback*)&plCB); + + size_t x; + + for (x = 0; x < files.size(); x ++) // temp record . replace it !!! + { + const wchar_t *fn = files.at(x)->Get(); + + validFile = checkFile(fn); + // can't use switch here cause break won't work + if (validFile == -1) // bad file and user cancelled + break; + if (validFile) // bad file, user skipped + { + allocRecordList(&newItems, newItems.Size + 1); + if (!newItems.Alloc) break; + + wchar_t title[2048] = {0}; + basicFileInfoStructW bfis = {fn, 0, 0, title, ARRAYSIZE(title) - 1,}; + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&bfis, IPC_GET_BASIC_FILE_INFOW); + if (bfis.length > 0) + { + memset((void *)&(newItems.Items[newItems.Size]), 0, sizeof(itemRecordW)); + newItems.Items[newItems.Size].filename = _wcsdup(fn); + newItems.Items[newItems.Size].title = _wcsdup(title); + newItems.Items[newItems.Size].length = bfis.length; + newItems.Size++; + } + } + delete(files.at(x)->Get()); + } + + if (validFile != -1) + copyRecordList(&itemCache[idx], &newItems); + refreshList(); + if (m_hwndstatus) SetStatus(m_hwndstatus, cLetter); + if (plManager) plmFactory->releaseInterface(plManager); +} +void cdburn_addfile(char* file, std::vector<GayString*> *files, api_playlistmanager* plManager, ifc_playlistloadercallback *plCB) +{ + if (!_stricmp(extension(file), "lnk")) + { + char temp2[MAX_PATH] = {0}; + if (ResolveShortCut(plugin.hwndLibraryParent, file, temp2)) lstrcpynA(file, temp2, MAX_PATH); + else return; + } + + if (!_strnicmp(file, "cda://", 6)) + { + if (strlen(file) == 7) + { + int n = 0; + char buf2[32] = {0}; + getFileInfo(file, "ntracks", buf2, sizeof(buf2)); + n = atoi(buf2); + if (n > 0 && n < 256) + { + for (int x = 0; x < n; x ++) + { + char s[64] = {0}; + StringCchPrintfA(s, 64, "%s,%d.cda", file, x + 1); + files->push_back(new GayString(s)); + } + } + } + else files->push_back(new GayString(file)); + } + + else if (strstr(file, "://")) + { + if (plManager && PLAYLISTMANAGER_SUCCESS != plManager->Load(AutoWide(file), plCB)) + { + files->push_back(new GayString(file)); + } + } + else if (!lstrcmpA(file + 1, ":\\")) + { + cdburn_addfolder(file, files, plManager, plCB); + } + else + { + WIN32_FIND_DATAA d = {0}; + HANDLE h = FindFirstFileA(file, &d); + if (h != INVALID_HANDLE_VALUE) + { + FindClose(h); + if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + cdburn_addfolder(file, files, plManager, plCB); + } + if (plManager && PLAYLISTMANAGER_SUCCESS != plManager->Load(AutoWide(file), plCB)) + { + files->push_back(new GayString(file)); + } + } + else files->push_back(new GayString(file)); + } +} +void cdburn_addfile(wchar_t* file, std::vector<GayStringW*> *files, api_playlistmanager* plManager, ifc_playlistloadercallback *plCB) +{ + if (!_wcsicmp(extensionW(file), L"lnk")) + { + wchar_t temp2[MAX_PATH] = {0}; + if (ResolveShortCut(plugin.hwndLibraryParent, file, temp2)) lstrcpyn(file, temp2, MAX_PATH); + else return; + } + + if (!_wcsnicmp(file, L"cda://", 6)) + { + if (wcslen(file) == 7) + { + int n = 0; + wchar_t buf2[32] = {0}; + getFileInfoW(file, L"ntracks", buf2, sizeof(buf2)); + n = _wtoi(buf2); + if (n > 0 && n < 256) + { + for (int x = 0; x < n; x ++) + { + wchar_t s[64] = {0}; + StringCchPrintfW(s, 64, L"%s,%d.cda", file, x + 1); + files->push_back(new GayStringW(s)); + } + } + } + else files->push_back(new GayStringW(file)); + } + + else if (wcsstr(file, L"://")) + { + if (plManager && PLAYLISTMANAGER_SUCCESS != plManager->Load(file, plCB)) + { + files->push_back(new GayStringW(file)); + } + } + else if (!lstrcmpW(file + 1, L":\\")) + { + cdburn_addfolder(file, files, plManager, plCB); + } + else + { + WIN32_FIND_DATAW d = {0}; + HANDLE h = FindFirstFileW(file, &d); + if (h != INVALID_HANDLE_VALUE) + { + FindClose(h); + if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + cdburn_addfolder(file, files, plManager, plCB); + } + if (plManager && PLAYLISTMANAGER_SUCCESS != plManager->Load(file, plCB)) + { + files->push_back(new GayStringW(file)); + } + } + else files->push_back(new GayStringW(file)); + } +} +void cdburn_addfolder(const char* folder, std::vector<GayString*> *files, api_playlistmanager* plManager, ifc_playlistloadercallback *plCB) +{ + WIN32_FIND_DATAA d = {0}; + char path[MAX_PATH] = {0}; + PathCombineA(path, folder, "*"); + + HANDLE h = FindFirstFileA(path, &d); + if (h == INVALID_HANDLE_VALUE) return; + do + { + if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (0 == lstrcmpA(d.cFileName, ".") || 0 == lstrcmpA(d.cFileName, "..")) continue; + GayString pathNew(folder); + pathNew.Append("\\"); + pathNew.Append(d.cFileName); + cdburn_addfolder(pathNew.Get(), files, plManager, plCB); + } + else + { + GayString file(folder); + file.Append("\\"); + file.Append(d.cFileName); + cdburn_addfile(file.Get(), files, plManager, plCB); + } + } + while (FindNextFileA(h, &d)); + FindClose(h); +} +void cdburn_addfolder(const wchar_t* folder, std::vector<GayStringW*> *files, api_playlistmanager* plManager, ifc_playlistloadercallback *plCB) +{ + WIN32_FIND_DATAW d = {0}; + wchar_t path[MAX_PATH] = {0}; + PathCombineW(path, folder, L"*"); + + HANDLE h = FindFirstFileW(path, &d); + if (h == INVALID_HANDLE_VALUE) return; + do + { + if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (0 == lstrcmpW(d.cFileName, L".") || 0 == lstrcmpW(d.cFileName, L"..")) continue; + GayStringW pathNew(folder); + pathNew.Append(L"\\"); + pathNew.Append(d.cFileName); + cdburn_addfolder(pathNew.Get(), files, plManager, plCB); + } + else + { + GayStringW file(folder); + file.Append(L"\\"); + file.Append(d.cFileName); + cdburn_addfile((wchar_t*)file.Get(), files, plManager, plCB); + } + } + while (FindNextFileW(h, &d)); + FindClose(h); +} +void cdburn_appendItemRecord(itemRecordList *obj, char cLetter) +{ + int idx = LETTERTOINDEX(cLetter); + int validFile = 1; + itemRecordListW newItems = {0, 0, 0}; + BurnAddStatus_Create(obj->Size); + + for (int i = 0;i < obj->Size;i++) + { + validFile = checkFile(obj->Items[i].filename); + if (validFile == -1) + break; + if (validFile) + { + if (newItems.Size > 255) break; + + allocRecordList(&newItems, newItems.Size + 1); + if (!newItems.Alloc) return ; + + memset((void *)&(newItems.Items[newItems.Size]), 0, sizeof(itemRecordW)); + newItems.Items[newItems.Size].filename = AutoWideDup(obj->Items[i].filename); + + GayString title; + if (obj->Items[i].artist) title.Append(obj->Items[i].artist); + if (title.Get() && title.Get()[0] && obj->Items[i].title && obj->Items[i].title[0]) + title.Append(" - "); + if (obj->Items[i].title) title.Append(obj->Items[i].title); + + newItems.Items[newItems.Size].title = AutoWideDup(title.Get()); + + newItems.Items[newItems.Size].length = obj->Items[i].length; + newItems.Size++; + BurnAddStatus_Step(&newItems); + } + } + BurnAddStatus_Done(); + if (validFile != -1) + copyRecordList(&itemCache[idx], &newItems); + refreshList(); + if (m_hwndstatus) SetStatus(m_hwndstatus, cLetter); +} + +void cdburn_appendItemRecord(itemRecordListW *obj, char cLetter) +{ + int idx = LETTERTOINDEX(cLetter); + int validFile = 1; + itemRecordListW newItems = {0, 0, 0}; + BurnAddStatus_Create(obj->Size); + + for (int i = 0;i < obj->Size;i++) + { + validFile = checkFile(obj->Items[i].filename); + if (validFile == -1) + break; + if (validFile) + { + if (newItems.Size > 255) break; + + allocRecordList(&newItems, newItems.Size + 1); + if (!newItems.Alloc) return ; + + memset((void *)&(newItems.Items[newItems.Size]), 0, sizeof(itemRecordW)); + newItems.Items[newItems.Size].filename = _wcsdup(obj->Items[i].filename); + + GayStringW title; + if (obj->Items[i].artist) title.Append(obj->Items[i].artist); + if (title.Get() && title.Get()[0] && obj->Items[i].title && obj->Items[i].title[0]) + title.Append(L" - "); + if (obj->Items[i].title) title.Append(obj->Items[i].title); + + newItems.Items[newItems.Size].title = _wcsdup(title.Get()); + + newItems.Items[newItems.Size].length = obj->Items[i].length; + newItems.Size++; + BurnAddStatus_Step(&newItems); + } + } + BurnAddStatus_Done(); + if (validFile != -1) + copyRecordList(&itemCache[idx], &newItems); + refreshList(); + if (m_hwndstatus) SetStatus(m_hwndstatus, cLetter); +} + +static void Shell_Free(void *p) +{ + IMalloc *m; + SHGetMalloc(&m); + m->Free(p); +} + +HWND cdburn_FindBurningHWND(char cLetter) +{ + HWND h = 0; + while (NULL != (h = FindWindowExW(NULL, h, L"#32770", NULL))) + { + if (!GetPropW(h, L"WABURNER")) continue; + if (((char)(INT_PTR)GetPropW(h, L"DRIVE")) == cLetter) return h; + } + return NULL; +} + +CHAR cdburn_IsMeBurning(void) +{ + if (pidBurner) + { + HWND h = NULL; + DWORD pid; + while (NULL != (h = FindWindowExW(NULL, h, L"#32770", NULL))) + { + if (GetPropW(h, L"WABURNER") && GetWindowThreadProcessId(h, &pid) && pid == pidBurner) + return (CHAR)(INT_PTR)GetPropW(h, L"DRIVE"); + } + } + return 0; +} + +static void NotifyInfoWindow(HWND hwnd, LPCWSTR pszFileName, BOOL bForceRefresh) +{ + HWND hwndParent; + hwndParent = GetParent(hwnd); + if (hwndParent) SendMessageW(hwndParent, WM_SHOWFILEINFO, + (WPARAM)((bForceRefresh) ? WISF_FORCE : WISF_NORMAL), + (LPARAM)pszFileName); +} + +static void moveSelItemsUp() +{ + if (DM_MODE_BURNING == DriveManager_GetDriveMode(m_cdrom)) return; + + int idx = LETTERTOINDEX(m_cdrom); + for (int i = 0;i < itemCache[idx].Size;i++) + { + if (m_statuslist.GetSelected(i)) + { + //swap the 2 items + if (i > 0) + { + itemRecordW tmp = itemCache[idx].Items[i]; + itemCache[idx].Items[i] = itemCache[idx].Items[i - 1]; + itemCache[idx].Items[i - 1] = tmp; + ListView_SetItemState(m_statuslist.getwnd(), i - 1, LVIS_SELECTED, LVIS_SELECTED); + ListView_SetItemState(m_statuslist.getwnd(), i, 0, LVIS_SELECTED); + ListView_RedrawItems(m_statuslist.getwnd(), i - 1, i); + if (ListView_GetItemState(m_statuslist.getwnd(), i, LVIS_FOCUSED)) + { + ListView_SetItemState(m_statuslist.getwnd(), i - 1, LVIS_FOCUSED, LVIS_FOCUSED); + } + } + } + } +} + +static void moveSelItemsDown() +{ + if (DM_MODE_BURNING == DriveManager_GetDriveMode(m_cdrom)) return ; + + int idx = LETTERTOINDEX(m_cdrom); + for (int i = itemCache[idx].Size - 1;i >= 0;i--) + { + if (m_statuslist.GetSelected(i)) + { + //swap the 2 items + if (i < (itemCache[idx].Size - 1)) + { + itemRecordW tmp = itemCache[idx].Items[i]; + itemCache[idx].Items[i] = itemCache[idx].Items[i + 1]; + itemCache[idx].Items[i + 1] = tmp; + ListView_SetItemState(m_statuslist.getwnd(), i + 1, LVIS_SELECTED, LVIS_SELECTED); + ListView_SetItemState(m_statuslist.getwnd(), i, 0, LVIS_SELECTED); + ListView_RedrawItems(m_statuslist.getwnd(), i, i + 1); + if (ListView_GetItemState(m_statuslist.getwnd(), i, LVIS_FOCUSED)) + { + ListView_SetItemState(m_statuslist.getwnd(), i + 1, LVIS_FOCUSED, LVIS_FOCUSED); + } + } + } + } +} + + +int g_burn_hack_startburn; + +void OnBurnDlgInit(HWND hwndDlg, LPARAM lParam) +{ + m_hwndstatus = hwndDlg; + m_is_cdrw = 0; + m_dragging = 0; + + m_cdrom = (char)lParam; + + SendMessageW(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(IDC_BTN_SHOWINFO, BN_EX_GETTEXT), (LPARAM)GetDlgItem(hwndDlg, IDC_BTN_SHOWINFO)); + + m_statuslist.setwnd(GetDlgItem(hwndDlg, IDC_LIST2)); + m_statuslist.AddCol(WASABI_API_LNGSTRINGW(IDS_TRACK_NUMBER), g_view_metaconf->ReadInt(L"col_track", 60)); + m_statuslist.AddCol(WASABI_API_LNGSTRINGW(IDS_TITLE), g_view_metaconf->ReadInt(L"col_title", 200)); + m_statuslist.AddCol(WASABI_API_LNGSTRINGW(IDS_LENGTH), g_view_metaconf->ReadInt(L"col_len", 80)); + m_statuslist.AddCol(WASABI_API_LNGSTRINGW(IDS_STATUS), g_view_metaconf->ReadInt(L"col_status", 200)); + + childSizer.Init(hwndDlg, burnwnd_rlist, sizeof(burnwnd_rlist) / sizeof(burnwnd_rlist[0])); + + if(m_statuslist.getwnd()) + { + MLSKINWINDOW sw; + + sw.hwndToSkin = m_statuslist.getwnd(); + sw.skinType = SKINNEDWND_TYPE_LISTVIEW; + sw.style = SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS | SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS; + MLSkinWindow(plugin.hwndLibraryParent, &sw); + } + + refreshList(); + + // this will make sure that we've got the cddb logo shown even when using a localised version + HANDLE hPrev = (HANDLE) SendDlgItemMessage(hwndDlg,IDC_LOGO,STM_SETIMAGE,IMAGE_BITMAP, + (LPARAM)LoadImage(plugin.hDllInstance,MAKEINTRESOURCE(IDB_LISTITEM_CDDRIVE), + IMAGE_BITMAP,0,0, 0)); + if (hPrev) DeleteObject(hPrev); + + NotifyInfoWindow(hwndDlg, NULL, TRUE); // ignore cache + SetStatus(hwndDlg, m_cdrom); + + if (g_burn_hack_startburn) + { + g_burn_hack_startburn = 0; + PostMessage(hwndDlg, WM_COMMAND, IDC_BURN, 0); + } + +} + +void OnBurnNotify(HWND hwndDlg, DWORD notification, DWORD param) +{ + switch (notification) + { + case BURN_READY: + SetStatus(hwndDlg, m_cdrom); + break; + case BURN_STATECHANGED: + { + wchar_t title[512] = {0}; + const wchar_t *buf = NULL; + switch (param) + { + case BURNERPLAYLIST_BURNCANCELING: + SetDlgItemText(hwndDlg, IDC_CANCEL_BURN, WASABI_API_LNGSTRINGW(IDS_CANCELLING)); + buf = WASABI_API_LNGSTRINGW_BUF(IDS_BURNING_AUDIO_CANCELLING,title,512); + break; + case BURNERPLAYLIST_BURNFINISHING: + buf = WASABI_API_LNGSTRINGW_BUF(IDS_BURNING_AUDIO_FINISHING,title,512); + break; + case BURNERPLAYLIST_DECODEFINISHED: + buf = WASABI_API_LNGSTRINGW_BUF(IDS_BURNING_AUDIO_DATA_PREP_FINISHED,title,512); + break; + case BURNERPLAYLIST_LICENSINGSTARTING: + buf = WASABI_API_LNGSTRINGW_BUF(IDS_BURNING_AUDIO_VERIFYING_FILES,title,512); + break; + case BURNERPLAYLIST_LICENSINGFINISHED: + buf = WASABI_API_LNGSTRINGW_BUF(IDS_BURNING_AUDIO_VERIFICATION_COMPLETED,title,512); + break; + case BURNERPLAYLIST_BURNPROGRESS: + wchar_t buf2[256] = {0}; + switch (SendMessage(m_burning_other_wnd, WM_BURNGETSTATUS, BURNSTATUS_ERROR, 0)) + { + case BURNERPLAYLIST_WRITELEADIN: + buf = WASABI_API_LNGSTRINGW_BUF(IDS_OPENING_DISC_WRITING_LEAD_IN,buf2,256); + break; + case BURNERPLAYLIST_WRITELEADOUT: + buf = WASABI_API_LNGSTRINGW_BUF(IDS_CLOSING_DISC_WRITING_LEAD_OUT,buf2,256); + break; + default: break; + } + if (buf) + { + int percent = (int)(INT_PTR)SendMessage(m_burning_other_wnd, WM_BURNGETSTATUS, BURNSTATUS_PROGRESS, 0); + percentCompleted = max(percent, percentCompleted); + StringCchPrintf(title, 512, WASABI_API_LNGSTRINGW(IDS_BURNING_AUDIO_CURRENT_OPERATION), percentCompleted, buf); + } + break; + } + if (buf) SetDlgItemText(hwndDlg, IDC_CDINFO, title); + } + break; + case BURN_ITEMSTATECHANGED: + ListView_RedrawItems(m_statuslist.getwnd(), param, param); + break; + case BURN_ITEMDECODEPROGRESS: + ListView_RedrawItems(m_statuslist.getwnd(), param, param); + { + wchar_t title[512] = {0}; + int percent = (int)(INT_PTR)SendMessage(m_burning_other_wnd, WM_BURNGETSTATUS, BURNSTATUS_PROGRESS, 0); + percentCompleted = max(percent, percentCompleted); + StringCchPrintf(title, 512, WASABI_API_LNGSTRINGW(IDS_BURNING_AUDIO_CD_PREP_DATA), percentCompleted); + SetDlgItemText(hwndDlg, IDC_CDINFO, title); + } + break; + case BURN_ITEMBURNPROGRESS: + ListView_RedrawItems(m_statuslist.getwnd(), param, param); + { + wchar_t title[512] = {0}; + int percent = (int)(INT_PTR)SendMessage(m_burning_other_wnd, WM_BURNGETSTATUS, BURNSTATUS_PROGRESS, 0); + percentCompleted = max(percent, percentCompleted); + StringCchPrintf(title, 512, WASABI_API_LNGSTRINGW(IDS_BURNING_AUDIO_BURNING_DATA), percentCompleted); + SetDlgItemText(hwndDlg, IDC_CDINFO, title); + } + break; + case BURN_WORKING: + ListView_RedrawItems(m_statuslist.getwnd(), 0, ListView_GetItemCount(m_statuslist.getwnd())); + break; + case BURN_FINISHED: + { + wchar_t buf1[128] = {0}, closeStr[16] = {0}; + GetDlgItemText(hwndDlg, IDC_CANCEL_BURN, buf1, ARRAYSIZE(buf1)); + if (lstrcmpi(buf1, WASABI_API_LNGSTRINGW_BUF(IDS_CLOSE,closeStr,16))) + SetDlgItemText(hwndDlg, IDC_CANCEL_BURN, closeStr); + wchar_t buf[128] = {0}; + switch (param) + { + case BURNERPLAYLIST_SUCCESS: + WASABI_API_LNGSTRINGW_BUF(IDS_AUDIO_CD_BURNED_SUCCESSFULLY,buf,128); + break; + case BURNERPLAYLIST_ABORTED: + WASABI_API_LNGSTRINGW_BUF(IDS_BURN_ABORTED_BY_USER,buf,128); + break; + default: + WASABI_API_LNGSTRINGW_BUF(IDS_BURNING_FAILED,buf,128); + break; + } + StringCchPrintf(buf1, 128, WASABI_API_LNGSTRINGW(IDS_BURNING_COMPLETED_STATUS_X), buf); + SetDlgItemText(hwndDlg, IDC_CDINFO, buf1); + EnableWindow(GetDlgItem(hwndDlg, IDC_BURN), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_BURN), TRUE); + } + break; + case BURN_DESTROYED: + EnableWindow(GetDlgItem(hwndDlg, IDC_BURN), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_BURN), TRUE); + m_burning_other_wnd = NULL; + SetStatus(hwndDlg, m_cdrom); + break; + case BURN_CONFIGCHANGED: + switch (LOWORD(param)) + { + case BURNCFG_AUTOCLOSE: + g_config->WriteInt(L"cdburnautoclose", HIWORD(param)); + break; + case BURNCFG_AUTOEJECT: + g_config->WriteInt(L"cdburnautoeject", HIWORD(param)); + break; + case BURNCFG_ADDTODB: + g_config->WriteInt(L"cdburnautoadddb", HIWORD(param)); + break; + case BURNCFG_HIDEVIEW: + g_config->WriteInt(L"cdburnstatuswnd", !HIWORD(param)); + break; + } + break; + } +} + +static int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + switch (uMsg) + { + case BFFM_INITIALIZED: + { + SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)WASABI_API_APP->path_getWorkingPath()); + + // this is not nice but it fixes the selection not working correctly on all OSes + EnumChildWindows(hwnd, browseEnumProc, 0); + } + } + return 0; +} + +wchar_t* BuildFilterList(void) +{ + static wchar_t fileExtensionsString[128] = {L"*.*"}; // "All files\0*.*\0\0" + wchar_t *temp=fileExtensionsString+lstrlenW(fileExtensionsString) +1; + lstrcpynW(temp, WASABI_API_LNGSTRINGW(IDS_ALL_FILES), 128); + *(temp = temp + lstrlenW(temp) + 1) = 0; + return fileExtensionsString; +} + + +static void CALLBACK Window_TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + HWND hwndList; + int index, driveIdx; + wchar_t *pszFileName; + + switch(idEvent) + { + case TIMER_NOTIFYINFO_ID: + KillTimer(hwnd, TIMER_NOTIFYINFO_ID); + hwndList = GetDlgItem(hwnd, IDC_LIST2); + + driveIdx = LETTERTOINDEX(m_cdrom); + index = (hwndList) ? (INT)SendMessage(hwndList, LVM_GETNEXTITEM, (WPARAM)-1, (LPARAM)LVNI_FOCUSED) : -1; + pszFileName = (index >= 0 && index < itemCache[driveIdx].Size) ? itemCache[driveIdx].Items[index].filename : NULL; + NotifyInfoWindow(hwnd, pszFileName, FALSE); + break; + } +} + +static void ListView_OnItemChanged(HWND hwndDlg, NMLISTVIEW *pnmv) +{ + if (LVIF_STATE & pnmv->uChanged) + { + if ((LVIS_FOCUSED & pnmv->uOldState) != (LVIS_FOCUSED & pnmv->uNewState)) + { + KillTimer(hwndDlg, TIMER_NOTIFYINFO_ID); + SetTimer(hwndDlg, TIMER_NOTIFYINFO_ID, TIMER_NOTIFYINFO_DELAY, Window_TimerProc); + } + } +} +static void Window_OnQueryInfo(HWND hwnd) +{ + KillTimer(hwnd, TIMER_NOTIFYINFO_ID); + NotifyInfoWindow(hwnd, NULL, TRUE); + SetTimer(hwnd, TIMER_NOTIFYINFO_ID, TIMER_NOTIFYINFO_DELAY, Window_TimerProc); +} + +static void Window_OnOperationCompleted(HWND hwnd, DM_NOTIFY_PARAM *phdr) +{ + MEDIAINFO mediaInfo; + + if (phdr->cLetter != m_cdrom) return; + + ZeroMemory(&mediaInfo, sizeof(MEDIAINFO)); + mediaInfo.cLetter = m_cdrom; + + switch(phdr->opCode) + { + case DMOP_IMAPIINFO: + if (S_OK == phdr->result) + { + DM_IMAPI_PARAM *pIMAPI = (DM_IMAPI_PARAM*)phdr; + + if ((0 != pIMAPI->fMediaType && 0 != pIMAPI->fMediaFlags)) + { + mediaInfo.bInserted = TRUE; + if (MEDIA_WRITABLE & pIMAPI->fMediaFlags) mediaInfo.bRecordable = TRUE; + if (MEDIA_RW & pIMAPI->fMediaFlags) mediaInfo.bRewritable = TRUE; + if (MEDIA_BLANK & pIMAPI->fMediaFlags) mediaInfo.bBlank = TRUE; + mediaInfo.nSectorsFree = pIMAPI->ulFreeBlocks; + mediaInfo.nSectorsUsed = pIMAPI->ulNextWritable; + } + } + else GetMediaInfoFromSonic(&mediaInfo); + FinishSetStatus(hwnd, &mediaInfo); + return; + } +} + +static INT_PTR CALLBACK DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + + INT_PTR a = dialogSkinner.Handle(hwndDlg, uMsg, wParam, lParam); if (a) return a; + switch (uMsg) + { + case WM_SIZE: + if (wParam != SIZE_MINIMIZED) + { + childSizer.Resize(hwndDlg, burnwnd_rlist, sizeof(burnwnd_rlist) / sizeof(burnwnd_rlist[0])); + } + break; + case WM_BURNNOTIFY: + OnBurnNotify(hwndDlg, (DWORD)wParam, (DWORD)lParam); + PostMessage(prevWnd, uMsg, wParam, lParam); + break; + case WM_INITDIALOG: OnBurnDlgInit(hwndDlg, lParam); return 0; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + // link is dead so disabling for the time being + /*case IDC_LOGO: + if (HIWORD(wParam) == BN_CLICKED) + ShellExecute(hwndDlg, L"open", L"http://estore.sonic.com/redirect.asp?id=spaol110103", NULL, L".", 0); + break;*/ + case IDC_BURN_OPTS: + { + RECT r; + HMENU menu = GetSubMenu(g_context_menus, 6); + GetWindowRect((HWND)lParam, &r); + CheckMenuItem(menu, ID_RIPOPTIONS_RIPPINGSTATUSWINDOW, g_config->ReadInt(L"cdburnstatuswnd", 0) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_EJECTCDWHENCOMPLETED, g_config->ReadInt(L"cdburnautoeject", 1) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_BURNOPTIONS_ADDCDTITLESTOLOCALCDDBCACHE, g_config->ReadInt(L"cdburnautoadddb", 1) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_CLOSEVIEWWHENCOMPLETE, g_config->ReadInt(L"cdburnautoclose", 0) ? MF_CHECKED : MF_UNCHECKED); + + int x = Menu_TrackPopup(plugin.hwndLibraryParent, menu, + TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_BOTTOMALIGN | + TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RETURNCMD, + r.left, r.top, hwndDlg, NULL); + int val = 0, msgid; + switch (x) + { + case ID_RIPOPTIONS_RIPPINGSTATUSWINDOW: + val = g_config->ReadInt(L"cdburnstatuswnd", 0); + g_config->WriteInt(L"cdburnstatuswnd", !val); + msgid = BURNCFG_HIDEVIEW; + break; + case ID_RIPOPTIONS_EJECTCDWHENCOMPLETED: + val = !g_config->ReadInt(L"cdburnautoeject", 1); + g_config->WriteInt(L"cdburnautoeject", val); + msgid = BURNCFG_AUTOEJECT; + break; + case ID_BURNOPTIONS_ADDCDTITLESTOLOCALCDDBCACHE: + val = !g_config->ReadInt(L"cdburnautoadddb", 0); + g_config->WriteInt(L"cdburnautoadddb", val); + msgid = BURNCFG_ADDTODB; + break; + case ID_RIPOPTIONS_CLOSEVIEWWHENCOMPLETE: + val = !g_config->ReadInt(L"cdburnautoclose", 0); + g_config->WriteInt(L"cdburnautoclose", val); + msgid = BURNCFG_AUTOCLOSE; + break; + default: msgid = 0; break; + } + if (msgid) + { + HWND h; + h = cdburn_FindBurningHWND(m_cdrom); + if (h) + { + PostMessage(h, WM_BURNCONFIGCHANGED, msgid, val); + if (BURNCFG_HIDEVIEW == msgid) ShowWindow(h, val ? SW_HIDE : SW_SHOW); + } + } + Sleep(100); + MSG msg; + while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); //eat return + } + return 0; + case IDC_ADD: + if (DM_MODE_BURNING != DriveManager_GetDriveMode(m_cdrom)) + { + RECT r; + GetWindowRect((HWND)lParam, &r); + int x = Menu_TrackPopup(plugin.hwndLibraryParent, GetSubMenu(g_context_menus, 3), + TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_BOTTOMALIGN | + TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RETURNCMD, + r.left, r.top, hwndDlg, NULL); + switch (x) + { + case ID_BURNADDMENU_FILES: + { + OPENFILENAMEW l = {sizeof(l), }; + wchar_t *temp; + const int len = 256 * 1024 - 128; + wchar_t *m_extlist = 0; + m_extlist = (wchar_t*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 1, IPC_GET_EXTLISTW); + if ((int)(INT_PTR)m_extlist == 1) m_extlist = 0; + + temp = (wchar_t *)GlobalAlloc(GPTR, len); + l.hwndOwner = hwndDlg; + l.lpstrFilter = m_extlist ? m_extlist : BuildFilterList(); + l.lpstrFile = temp; + l.nMaxFile = len - 1; + l.lpstrTitle = WASABI_API_LNGSTRINGW(IDS_ADD_FILES_TO_BURNING_LIST); + l.lpstrDefExt = L""; + l.lpstrInitialDir = WASABI_API_APP->path_getWorkingPath(); + + l.Flags = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ALLOWMULTISELECT; + if (GetOpenFileNameW(&l)) + { + wchar_t newCurPath[MAX_PATH] = {0}; + GetCurrentDirectoryW(MAX_PATH, newCurPath); + WASABI_API_APP->path_setWorkingPath(newCurPath); + + if (temp[wcslen(temp) + 1]) + { + wchar_t buf[MAX_PATH] = {0}; + wchar_t *p = temp; + wchar_t *path = p; + p += wcslen(p) + 1; + while (p && *p) + { + if (*path) + StringCchPrintfW(buf, MAX_PATH, L"%s%s%s", path, path[wcslen(path) - 1] == '\\' ? L"" : L"\\" , p); + else + StringCchPrintfW(buf, MAX_PATH, L"%s", p); + + cdburn_appendFile(buf, m_cdrom); + p += wcslen(p) + 1; + } + } + else + cdburn_appendFile(temp, m_cdrom); + } + GlobalFree(temp); + if (m_extlist) GlobalFree((HGLOBAL)m_extlist); + SetStatus(hwndDlg, m_cdrom); + } + break; + case ID_BURNADDMENU_FOLDER: + { + BROWSEINFOW bi = {0}; + wchar_t name[MAX_PATH] = {0}; + bi.hwndOwner = hwndDlg; + bi.pszDisplayName = name; + bi.lpszTitle = WASABI_API_LNGSTRINGW(IDS_CHOOSE_A_FOLDER_TO_ADD_TO_BURNING_LIST); + bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; + bi.lpfn = BrowseCallbackProc; + ITEMIDLIST *idlist = SHBrowseForFolderW(&bi); + if (idlist) + { + wchar_t path[MAX_PATH] = {0}; + SHGetPathFromIDListW(idlist, path); + Shell_Free(idlist); + cdburn_appendFile(path, m_cdrom); + SetStatus(hwndDlg, m_cdrom); + } + } + break; + case ID_BURNADDMENU_CURRENTPLAYLIST: + { + int plsize = (int)(INT_PTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETLISTLENGTH); + for (int i = 0;i < plsize;i++) + { + wchar_t *name = (wchar_t *)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, i, IPC_GETPLAYLISTFILEW); + cdburn_appendFile(name, m_cdrom); + } + SetStatus(hwndDlg, m_cdrom); + } + break; + } + Sleep(100); + MSG msg; + while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); //eat return + } + break; + case IDC_CLEAR: + if (DM_MODE_BURNING != DriveManager_GetDriveMode(m_cdrom)) + { + wchar_t title[32] = {0}; + if (MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_SURE_YOU_WANT_TO_CLEAR_BURNING_LIST), + WASABI_API_LNGSTRINGW_BUF(IDS_CONFIRMATION,title,32), MB_YESNO) != IDYES) + break; + emptyRecordList(&itemCache[LETTERTOINDEX(m_cdrom)]); + SetStatus(hwndDlg, m_cdrom); + refreshList(); + } + break; + case IDC_CANCEL_BURN: + case IDC_BURN: + { + HWND h; + if (NULL != (h = cdburn_FindBurningHWND(m_cdrom))) + { + PostMessage(h, WM_COMMAND, MAKEWPARAM(IDCANCEL, BN_CLICKED), 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_BURN), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_BURN), FALSE); + + } + else doBurnDialog(hwndDlg); + } + break; + case IDC_BTN_SHOWINFO: + switch(HIWORD(wParam)) + { + case BN_CLICKED: SendMessageW(GetParent(hwndDlg), WM_COMMAND, wParam, lParam); break; + } + break; + } + break; + + case WM_CONTEXTMENU: + { + if (DM_MODE_BURNING == DriveManager_GetDriveMode(m_cdrom) || m_statuslist.GetCount() == 0) return 0; + + HMENU menu = GetSubMenu(g_context_menus, 4); + + POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; + + if (pt.x == -1 || pt.y == -1) // x and y are -1 if the user invoked a shift-f10 popup menu + { + RECT itemRect = {0}; + int selected = m_statuslist.GetNextSelected(); + if (selected != -1) // if something is selected we'll drop the menu from there + { + m_statuslist.GetItemRect(selected, &itemRect); + ClientToScreen(m_statuslist.getwnd(), (POINT *)&itemRect); + } + else // otherwise we'll drop it from the top-left corner of the listview, adjusting for the header location + { + GetWindowRect(m_statuslist.getwnd(), &itemRect); + + HWND hHeader = (HWND)SNDMSG((HWND)wParam, LVM_GETHEADER, 0, 0L); + RECT headerRect; + if ((WS_VISIBLE & GetWindowLongPtr(hHeader, GWL_STYLE)) && GetWindowRect(hHeader, &headerRect)) + { + itemRect.top += (headerRect.bottom - headerRect.top); + } + } + pt.x = itemRect.left; + pt.y = itemRect.top; + } + + HWND hHeader = (HWND)SNDMSG((HWND)wParam, LVM_GETHEADER, 0, 0L); + RECT headerRect; + if (0 == (WS_VISIBLE & GetWindowLongPtr(hHeader, GWL_STYLE)) || FALSE == GetWindowRect(hHeader, &headerRect)) + { + SetRectEmpty(&headerRect); + } + + if (FALSE != PtInRect(&headerRect, pt)) + { + return 0; + } + + int r = Menu_TrackPopup(plugin.hwndLibraryParent, menu, + TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_NONOTIFY, + pt.x, pt.y, hwndDlg, NULL); + switch (r) + { + case ID_BURNCONTEXTMENU_PLAYSELECTEDITEMS: + playSelectedItems(hwndDlg, 0); + break; + case ID_BURNCONTEXTMENU_ENQUEUESELECTEDITEMS: + playSelectedItems(hwndDlg, 1); + break; + case ID_BURNCONTEXTMENU_SELECTALL: + selectAll(); + break; + case ID_BURNCONTEXTMENU_REMOVESELECTEDITEMS: + if (DM_MODE_BURNING != DriveManager_GetDriveMode(m_cdrom)) deleteSelectedItems(hwndDlg, m_cdrom); + break; + case ID_BURNCONTEXTMENU_BURN: + doBurnDialog(hwndDlg); + break; + case ID_BURNCONTEXTMENU_MOVESELECTEDITEMSUP: + moveSelItemsUp(); + break; + case ID_BURNCONTEXTMENU_MOVESELECTEDITEMSDOWN: + moveSelItemsDown(); + break; + } + Sleep(100); + MSG msg; + while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); //eat return + return 1; + } + + case WM_NOTIFY: + { + LPNMHDR l = (LPNMHDR)lParam; + if (l->idFrom == IDC_LIST2) + { + if (l->code == LVN_KEYDOWN) + { + LPNMLVKEYDOWN pnkd = (LPNMLVKEYDOWN) lParam; + switch (pnkd->wVKey) + { + case 38: //up + if (GetAsyncKeyState(VK_LMENU)) + { + moveSelItemsUp(); + return 1; + } + break; + case 40: //down + if (GetAsyncKeyState(VK_LMENU)) + { + moveSelItemsDown(); + return 1; + } + break; + case 46: //delete + if (DM_MODE_BURNING != DriveManager_GetDriveMode(m_cdrom)) deleteSelectedItems(hwndDlg, m_cdrom); + break; + case 'A': + if (GetAsyncKeyState(VK_CONTROL)) + selectAll(); + break; + } + } + else if (l->code == NM_DBLCLK) + { + if (DM_MODE_BURNING == DriveManager_GetDriveMode(m_cdrom)) return 0; + playSelectedItems(hwndDlg, (!!g_config->ReadInt(L"enqueuedef", 0)) ^(!!(GetAsyncKeyState(VK_SHIFT)&0x8000))); + } + else if (l->code == NM_RETURN) + { + if (DM_MODE_BURNING == DriveManager_GetDriveMode(m_cdrom)) return 0; + playSelectedItems(hwndDlg, 0 ^(!!(GetAsyncKeyState(VK_SHIFT)&0x8000))); + } + else if (l->code == LVN_GETDISPINFO) + { + NMLVDISPINFO *lpdi = (NMLVDISPINFO*) lParam; + int item = lpdi->item.iItem; + int idx = LETTERTOINDEX(m_cdrom); + if (item < 0 || item >= itemCache[idx].Size) return 0; + + itemRecordW *thisitem = itemCache[idx].Items + item; + + if (lpdi->item.mask & (LVIF_TEXT | /*LVIF_IMAGE*/0)) // we can always do images too :) + { + if (lpdi->item.mask & LVIF_TEXT) + { + wchar_t tmpbuf[128] = {0}; + wchar_t *nameptr = 0; + switch (lpdi->item.iSubItem) + { + case 0: + //track # + StringCchPrintfW(tmpbuf, 128, L"%d", item + 1); + nameptr = tmpbuf; + break; + case 1: + //title + lstrcpynW(tmpbuf, thisitem->title, 128); + nameptr = tmpbuf; + break; + case 2: + //length + StringCchPrintfW(tmpbuf, 128, L"%01d:%02d", thisitem->length / 60, thisitem->length % 60); + nameptr = tmpbuf; + break; + case 3: + DWORD state = (DWORD) SendMessage(m_burning_other_wnd, WM_BURNGETITEMSTATUS, BURNSTATUS_STATE, (LPARAM)item); + switch (state) + { + case BURNERITEM_BURNING: + case BURNERITEM_DECODING: + StringCchPrintfW(tmpbuf, 128, L"%s (%d%%)", + WASABI_API_LNGSTRINGW((BURNERITEM_BURNING == state) ? IDS_BURNING_ : IDS_PREPARING), + (DWORD)SendMessage(m_burning_other_wnd, WM_BURNGETITEMSTATUS, BURNSTATUS_PROGRESS, (LPARAM)item)); + nameptr = tmpbuf; + break; + case BURNERITEM_SUCCESS: break; + case BURNERITEM_BURNED: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_FINISHED,tmpbuf,128); + break; + case BURNERITEM_DECODED: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_PREPARED,tmpbuf,128); + break; + case BURNERITEM_SKIPPED: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_SKIPPED,tmpbuf,128); + break; + case BURNERITEM_READY: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_SCHEDULED,tmpbuf,128); + break; + case BURNERITEM_LICENSING: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_CHECKING_LICENSE,tmpbuf,128); + break; + case BURNERITEM_LICENSED: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_LICENSED,tmpbuf,128); + break; + case BURNERITEM_ABORTED: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_CANCELLED,tmpbuf,128); + break; + case BURNERITEM_FAILED: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_FAILED,tmpbuf,128); + break; + case BURNERITEM_CANCELING: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_CANCELLING,tmpbuf,128); + break; + case BURNERITEM_BADFILENAME: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_BAD_FILENAME,tmpbuf,128); + break; + case BURNERITEM_UNABLEOPENFILE: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_UNABLE_TO_OPEN_FILE,tmpbuf,128); + break; + case BURNERITEM_WRITEERROR: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_CACHE_WRITE_FAILED,tmpbuf,128); + break; + case BURNERITEM_DECODEERROR: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_UNABLE_TO_FIND_DECODER,tmpbuf,128); + break; + case BURNERITEM_ADDSTREAMFAILED: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_CANNOT_ADD_TO_THE_DISC,tmpbuf,128); + break; + case BURNERITEM_READSTREAMERROR: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_CACHE_READ_FAILED,tmpbuf,128); + break; + default: + nameptr = WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN_ERROR,tmpbuf,128); + break; + } + //status + break; + } + if (nameptr) + lstrcpynW(lpdi->item.pszText, nameptr, lpdi->item.cchTextMax); + else + lpdi->item.pszText[0] = 0; + } + } + return 0; + } + else if (l->code == LVN_BEGINDRAG) + { + SetCapture(hwndDlg); + m_dragging = 1; + LPNMLISTVIEW nlv = (LPNMLISTVIEW)lParam; + m_drag_item = nlv->iItem; + } + else if (l->code == LVN_ITEMCHANGED) ListView_OnItemChanged(hwndDlg, (NMLISTVIEW*)l); + } + } + break; + + case WM_MOUSEMOVE: + if (m_dragging) + { + POINT p; + p.x = GET_X_LPARAM(lParam); + p.y = GET_Y_LPARAM(lParam); + ClientToScreen(hwndDlg, &p); + ScreenToClient(m_statuslist.getwnd(), &p); + int i = m_statuslist.FindItemByPoint(p.x, p.y); + if (i != -1 && i != m_drag_item) + { + if (i > m_drag_item) + { + for (int j = 0;j < (i - m_drag_item);j++) + moveSelItemsDown(); + } + else + { + for (int j = 0;j < (m_drag_item - i);j++) + moveSelItemsUp(); + } + m_drag_item = i; + } + } + break; + + case WM_LBUTTONUP: + if (GetCapture() == hwndDlg) + { + ReleaseCapture(); + m_dragging = 0; + } + break; + + case WM_DESTROY: + if (m_statuslist.getwnd()) + { + g_view_metaconf->WriteInt(L"col_track", m_statuslist.GetColumnWidth(0)); + g_view_metaconf->WriteInt(L"col_title", m_statuslist.GetColumnWidth(1)); + g_view_metaconf->WriteInt(L"col_len", m_statuslist.GetColumnWidth(2)); + g_view_metaconf->WriteInt(L"col_status", m_statuslist.GetColumnWidth(3)); + } + + if (m_burning_other_wnd && IsWindow(m_burning_other_wnd)) + { + PostMessage(m_burning_other_wnd, WM_BURNUPDATEOWNER, 0, (LPARAM)prevWnd); + prevWnd = NULL; + } + m_hwndstatus = 0; + + if (hPLFont) + { + DeleteObject(hPLFont); + hPLFont = NULL; + } + + { + HANDLE hPrev = (HANDLE) SendDlgItemMessage(hwndDlg,IDC_LOGO,STM_SETIMAGE,IMAGE_BITMAP, 0L); + if (hPrev) DeleteObject(hPrev); + } + return 0; + case WM_ML_CHILDIPC: + if (lParam == ML_CHILDIPC_DROPITEM && wParam) + { + mlDropItemStruct *dis = (mlDropItemStruct *)wParam; + if (DM_MODE_BURNING == DriveManager_GetDriveMode(m_cdrom)) + { + dis->result = -1; + return 0; + } + + if (dis->type != ML_TYPE_ITEMRECORDLISTW && dis->type != ML_TYPE_ITEMRECORDLIST && + dis->type != ML_TYPE_FILENAMES && dis->type != ML_TYPE_FILENAMESW) + { + dis->result = -1; + } + else + { + if (dis->data) + { + dis->result = 1; + if (dis->type == ML_TYPE_ITEMRECORDLIST) + { + itemRecordList *obj = (itemRecordList *)dis->data; + cdburn_appendItemRecord(obj, m_cdrom); + } + else if (dis->type == ML_TYPE_ITEMRECORDLISTW) + { + itemRecordListW *obj = (itemRecordListW *)dis->data; + cdburn_appendItemRecord(obj, m_cdrom); + } + else if (dis->type == ML_TYPE_FILENAMES) // playlist + { + char *p = (char*)dis->data; + while (p && *p) + { + cdburn_appendFile(p, m_cdrom); + p += strlen(p) + 1; + } + } + else if (dis->type == ML_TYPE_FILENAMESW) + { + wchar_t *p = (wchar_t*)dis->data; + while (p && *p) + { + cdburn_appendFile(p, m_cdrom); + p += wcslen(p) + 1; + } + } + } + } + } + return 0; + + case WM_DROPFILES: + { + char temp[2048] = {0}; + HDROP h = (HDROP) wParam; + int y = DragQueryFileA(h, 0xffffffff, temp, sizeof(temp)); + + if (DM_MODE_BURNING == DriveManager_GetDriveMode(m_cdrom)) + { +// MessageBoxA(hwndDlg,"Cannot add files while burning","CD Burner",MB_OK); + } + else for (int x = 0; x < y; x ++) + { + DragQueryFileA(h, x, temp, sizeof(temp)); + cdburn_appendFile(temp, m_cdrom); + } + + DragFinish(h); + } + return 0; + case WM_PAINT: + { + int tab[] = { IDC_LIST2 | DCW_SUNKENBORDER, IDC_LOGO | DCW_SUNKENBORDER}; + dialogSkinner.Draw(hwndDlg, tab, 2); + } + return 0; + case WM_ERASEBKGND: return 1; //handled by WADlg_DrawChildWindowBorders in WM_PAINT + case WM_QUERYFILEINFO: Window_OnQueryInfo(hwndDlg); break; + case WM_EX_OPCOMPLETED: Window_OnOperationCompleted(hwndDlg, (DM_NOTIFY_PARAM*)lParam); + } + return FALSE; +} + +static HWND BurnAddStatus_wnd; + +static BOOL CALLBACK BurnAddStatus_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (uMsg == WM_CLOSE) + DestroyWindow(hwndDlg); + return 0; +} + +void BurnAddStatus_Create(int num) +{ + if (BurnAddStatus_wnd && IsWindow(BurnAddStatus_wnd)) DestroyWindow(BurnAddStatus_wnd); + BurnAddStatus_wnd = WASABI_API_CREATEDIALOGW(IDD_BURN_ADD_STATUS, plugin.hwndLibraryParent, BurnAddStatus_proc); + if (!BurnAddStatus_wnd) return ; + + SetTimer(BurnAddStatus_wnd, 1, 100, NULL); + SendDlgItemMessage(BurnAddStatus_wnd, IDC_PROGRESS1, PBM_SETRANGE, 0, MAKELPARAM(0, num)); + + unsigned int start_t = GetTickCount(); + if (start_t >= 0xffffff00) start_t = 0; + + MSG msg; + while (GetTickCount() < start_t + 100 && GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void BurnAddStatus_Step(itemRecordListW *items) +{ + if (!BurnAddStatus_wnd || !items || items && !items->Size || items && !items->Items) return ; + SendDlgItemMessage(BurnAddStatus_wnd, IDC_PROGRESS1, PBM_DELTAPOS, 1, 0); + + int l = 0; + for (int i = 0;i < items->Size;i++) + { + l += items->Items[i].length; + } + wchar_t buf[512] = {0}; + StringCchPrintf(buf, 512, WASABI_API_LNGSTRINGW(IDS_ADDING_TRACKS_TO_BURNER_TOTAL_LENGTH_X), l / 60, l % 60); + SetDlgItemText(BurnAddStatus_wnd, IDC_STAT, buf); +} + +void BurnAddStatus_Done() +{ + if (!BurnAddStatus_wnd) return ; + unsigned int start_t = GetTickCount(); + if (start_t >= 0xffffff00) start_t = 0; + + MSG msg; + while (GetTickCount() < start_t + 1000 && IsWindow(BurnAddStatus_wnd) && GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + DestroyWindow(BurnAddStatus_wnd); + BurnAddStatus_wnd = 0; +} + +static bool cdrFound(char letter) +{ + wchar_t name[]= L"cda://X.cda"; + wchar_t info[16] = L""; + name[6] = letter; + getFileInfoW(name, L"cdtype", info, sizeof(info)/sizeof(wchar_t)); + return !lstrcmpW(info, L"CDR") || !lstrcmpW(info, L"CDRW"); +} + +static char m_burnwait_letter; +static BOOL CALLBACK BurnWaitProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + SetTimer(hwndDlg, 1, 2000, NULL); + { + wchar_t buf[512] = {0}; + StringCchPrintf(buf, 512, WASABI_API_LNGSTRINGW(IDS_PLEASE_INSERT_BLANK_RECORDABLE_CD), toupper(m_burnwait_letter)); + SetDlgItemText(hwndDlg, IDC_TEXT, buf); + } + return 0; + case WM_COMMAND: + if (LOWORD(wParam) == IDCANCEL) EndDialog(hwndDlg, 1); + return 0; + case WM_TIMER: + if (cdrFound(m_burnwait_letter)) EndDialog(hwndDlg, 0); + return 0; + } + return 0; +} + +int Burn_WaitForCDR(HWND hwndParent, char driveletter) // returns 0 on CD-R found, 1 on cancel +{ + CHAR cMode; + if (!driveletter) return 1; + cMode = DriveManager_GetDriveMode(driveletter); + if (DM_MODE_BURNING == cMode || DM_MODE_RIPPING == cMode) + { + return 1; // if burning or ripping, don't fuck with it + } + + if (cdrFound(driveletter)) return 0; + if (m_burnwait_letter) return 1; + + m_burnwait_letter = (char)toupper(driveletter); + int x = (int)(INT_PTR)WASABI_API_DIALOGBOXW(IDD_WAITFORCDR, hwndParent, BurnWaitProc); + m_burnwait_letter = 0; + return x; +} diff --git a/Src/Plugins/Library/ml_disc/cdrip.cpp b/Src/Plugins/Library/ml_disc/cdrip.cpp new file mode 100644 index 00000000..58192596 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/cdrip.cpp @@ -0,0 +1,1061 @@ +#include "main.h" +#include <windowsx.h> +#include "resource.h" + +#include "..\nu\listview.h" +#include "../nu/DialogSkinner.h" +#include "../nu/ChildSizer.h" + +#include "config.h" +#include "../winamp/wa_ipc.h" + +#include "..\..\General\gen_ml/gaystring.h" + +#include <stdio.h> +#include <shlobj.h> +#include <time.h> +#include "../nu/AutoChar.h" +#include "../nu/AutoCharFn.h" +#include "../nu/AutoWide.h" + +#include "ReplayGain.h" + +#include "M3UWriter.h" +#include "PLSWriter.h" +#include "./settings.h" +#include <shlwapi.h> +#include <windows.h> +#include <strsafe.h> + +extern unsigned int FileTimeToUnixTime(FILETIME *ft); + +static UINT uMsgRipperNotify = 0; + + +static INT_PTR WINAPI DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +HWND CreateCDRipWindow(HWND hwndParent, CHAR cLetter) +{ + return WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_CDROM_EX2, hwndParent, DlgProc, (LPARAM)cLetter); +} +//physically update metadata in a given file +int updateFileInfo(char *filename, char *metadata, char *data) +{ + extendedFileInfoStruct efis = { + filename, + metadata, + data ? data : "", + data ? strlen(data) : 0, + }; + return (INT)(INT_PTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&efis, IPC_SET_EXTENDED_FILE_INFO); +} + +//physically update metadata in a given file +int updateFileInfoW(wchar_t *filename, const wchar_t *metadata, const wchar_t *data) +{ + extendedFileInfoStructW efis = { + filename, + metadata, + data ? data : L"", + data ? lstrlenW(data) : 0, + }; + return (INT)(INT_PTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&efis, IPC_SET_EXTENDED_FILE_INFOW); +} + + +static int m_extract_curtrack, m_extract_nb, m_extract_nb_total; +static int m_db_has_upd; +static convertFileStructW m_fcs; +static wchar_t m_extract_src[64]; +static DWORD m_extract_time; +static int m_extracting; +static cdrip_params *m_rip_params; +HWND m_extract_wnd = 0; +static wchar_t m_last_total_status[512]; +static wchar_t m_last_item_status[512]; +static int m_cur_rg = 0; +static int done = 0; + +bool RegisteredEncoder(DWORD fourcc) +{ + if (fourcc == mmioFOURCC('M', 'P', '3', 'l') + || fourcc == mmioFOURCC('A', 'A', 'C', 'H') + || fourcc == mmioFOURCC('M', '4', 'A', 'H')) + return true; + else + return false; +} + +static void createDirForFile(char *str) +{ + char *p = str; + if ((p[0] == '\\' || p[0] == '/') && (p[1] == '\\' || p[1] == '/')) + { + p += 2; + while (p && *p && *p != '\\' && *p != '/') p++; + if (!p || !*p) return ; + p++; + while (p && *p && *p != '\\' && *p != '/') p++; + } + else + { + while (p && *p && *p != '\\' && *p != '/') p++; + } + + while (p && *p) + { + while (p && *p != '\\' && *p != '/' && *p) p = CharNextA(p); + if (p && *p) + { + char lp = *p; + *p = 0; + CreateDirectoryA(str, NULL); + *p++ = lp; + } + } +} + +static void createDirForFileW(wchar_t *str) +{ + wchar_t *p = str; + if ((p[0] ==L'\\' || p[0] ==L'/') && (p[1] ==L'\\' || p[1] ==L'/')) + { + p += 2; + while (p && *p && *p !=L'\\' && *p !=L'/') p++; + if (!p || !*p) return ; + p++; + while (p && *p && *p !=L'\\' && *p !=L'/') p++; + } + else + { + while (p && *p && *p !=L'\\' && *p !=L'/') p++; + } + + while (p && *p) + { + while (p && *p !=L'\\' && *p !=L'/' && *p) p = CharNextW(p); + if (p && *p) + { + wchar_t lp = *p; + *p = 0; + CreateDirectoryW(str, NULL); + *p++ = lp; + } + } +} + +static void LockCD(char cLetter, BOOL bLock) +{ + wchar_t info[32] = {0}; + wchar_t name[] = L"cda://X"; + name[6] = cLetter; + getFileInfoW(name, (bLock) ? L"cdlock" : L"cdunlock", info, sizeof(info)/sizeof(wchar_t)); +} + +static int m_pstat_bytesdone; +static int m_pstat_bytesout; +static int m_pstat_timedone; + +static int m_rip_done; + +static HWND m_hwndstatus; +static W_ListView m_statuslist; + +static void NotifyInfoWindow(HWND hwnd, BOOL bForceRefresh) +{ + HWND hwndParent; + hwndParent = GetParent(hwnd); + if (hwndParent) SendMessageW(hwndParent, WM_SHOWFILEINFO, + (WPARAM) WISF_MESSAGE | ((bForceRefresh) ? WISF_FORCE : WISF_NORMAL), + (LPARAM)WASABI_API_LNGSTRINGW(IDS_INFO_RIPPING)); +} + +static void ListView_OnItemChanged(HWND hwndDlg, NMLISTVIEW *pnmv) +{ + if (LVIF_STATE & pnmv->uChanged) + { + if ((LVIS_FOCUSED & pnmv->uOldState) != (LVIS_FOCUSED & pnmv->uNewState)) + { + NotifyInfoWindow(hwndDlg, TRUE); + } + } +} + +static void Window_OnQueryInfo(HWND hwnd) +{ + NotifyInfoWindow(hwnd, FALSE); +} + +static INT_PTR Window_OnNotify(HWND hwndDlg, INT ctrlId, LPNMHDR phdr) +{ + switch(phdr->idFrom) + { + case IDC_LIST2: + switch(phdr->code) + { + case LVN_ITEMCHANGED: ListView_OnItemChanged(hwndDlg, (NMLISTVIEW*)phdr); break; + } + break; + } + return 0; +} + +INT_PTR WINAPI DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static ChildWndResizeItem ripwnd_rlist[] = { + {IDC_LIST2, 0x0011}, + {IDC_CDINFO, 0x0000}, + {IDC_RIPOPTS, 0x0101}, + {IDC_CANCEL_RIP, 0x0101}, + {IDC_BTN_SHOWINFO, 0x1111}, + }; + + INT_PTR a = (INT_PTR)dialogSkinner.Handle(hwndDlg, uMsg, wParam, lParam); if (a) return a; + switch (uMsg) + { + case WM_SIZE: + if (wParam != SIZE_MINIMIZED) + { + childSizer.Resize(hwndDlg, ripwnd_rlist, sizeof(ripwnd_rlist) / sizeof(ripwnd_rlist[0])); + } + break; + case WM_PAINT: + { + int tab[] = { IDC_LIST2 | DCW_SUNKENBORDER}; + dialogSkinner.Draw(hwndDlg, tab, 1); + } + return 0; + case WM_INITDIALOG: + + m_hwndstatus = hwndDlg; + + SendMessageW(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(IDC_BTN_SHOWINFO, BN_EX_GETTEXT), (LPARAM)GetDlgItem(hwndDlg, IDC_BTN_SHOWINFO)); + + m_statuslist.setwnd(GetDlgItem(hwndDlg, IDC_LIST2)); + m_statuslist.AddCol(WASABI_API_LNGSTRINGW(IDS_TRACK_NUMBER), g_view_metaconf->ReadInt(L"col_track", 60)); + m_statuslist.AddCol(WASABI_API_LNGSTRINGW(IDS_TITLE), g_view_metaconf->ReadInt(L"col_title", 200)); + m_statuslist.AddCol(WASABI_API_LNGSTRINGW(IDS_LENGTH), g_view_metaconf->ReadInt(L"col_len", 80)); + m_statuslist.AddCol(WASABI_API_LNGSTRINGW(IDS_STATUS), g_view_metaconf->ReadInt(L"col_status", 200)); + + SetDlgItemText(hwndDlg, IDC_CDINFO, m_last_total_status); + { + int l = m_rip_params->ntracks; + int x = 0; + for (int i = 0;i < l;i++) if (m_rip_params->tracks[i]) + { + wchar_t buf[1024] = {0}; + StringCchPrintf(buf, 1024, L"%d", i + 1); + m_statuslist.InsertItem(x, buf, 0); + m_statuslist.SetItemText(x, 1, m_rip_params->tracks[i]); + + StringCchPrintf(buf, 512, L"%d:%02d", m_rip_params->lengths[i] / 60, m_rip_params->lengths[i] % 60); + m_statuslist.SetItemText(x, 2, buf); + + if (i < m_extract_curtrack || m_rip_done) + m_statuslist.SetItemText(x, 3, WASABI_API_LNGSTRINGW(IDS_COMPLETED)); + else if (i > m_extract_curtrack) + m_statuslist.SetItemText(x, 3, WASABI_API_LNGSTRINGW(IDS_QUEUED)); + else + { + m_statuslist.SetItemText(x, 3, m_last_item_status[0] ? m_last_item_status : WASABI_API_LNGSTRINGW(IDS_RIPPING)); + } + x++; + } + } + + if (!m_extract_wnd || m_rip_done) + { + SetDlgItemText(hwndDlg, IDC_CANCEL_RIP, WASABI_API_LNGSTRINGW(IDS_CLOSE)); + } + + if (g_config->ReadInt(L"cdripautoeject", 0)) CheckDlgButton(hwndDlg, IDC_CHECK2, BST_CHECKED); + if (g_config->ReadInt(L"cdripautoplay", 0)) CheckDlgButton(hwndDlg, IDC_CHECK3, BST_CHECKED); + if (g_config->ReadInt(L"cdripautoclose", 1)) CheckDlgButton(hwndDlg, IDC_CHECK1, BST_CHECKED); + + childSizer.Init(hwndDlg, ripwnd_rlist, sizeof(ripwnd_rlist) / sizeof(ripwnd_rlist[0])); + + ListView_SetTextColor(m_statuslist.getwnd(), dialogSkinner.Color(WADLG_ITEMFG)); + ListView_SetBkColor(m_statuslist.getwnd(), dialogSkinner.Color(WADLG_ITEMBG)); + ListView_SetTextBkColor(m_statuslist.getwnd(), dialogSkinner.Color(WADLG_ITEMBG)); + + if(m_statuslist.getwnd()) + { + MLSKINWINDOW sw; + sw.hwndToSkin = m_statuslist.getwnd(); + sw.skinType = SKINNEDWND_TYPE_LISTVIEW; + sw.style = SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS | SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS; + MLSkinWindow(plugin.hwndLibraryParent, &sw); + } + NotifyInfoWindow(hwndDlg, TRUE); + return 0; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_RIPOPTS: + { + RECT r; + HMENU menu = GetSubMenu(g_context_menus, 5); + GetWindowRect((HWND)lParam, &r); + CheckMenuItem(menu, ID_RIPOPTIONS_RIPPINGSTATUSWINDOW, g_config->ReadInt(L"cdripstatuswnd", 0) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_EJECTCDWHENCOMPLETED, g_config->ReadInt(L"cdripautoeject", 0) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_PLAYTRACKSWHENCOMPLETED, g_config->ReadInt(L"cdripautoplay", 0) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_CLOSEVIEWWHENCOMPLETE, g_config->ReadInt(L"cdripautoclose", 0) ? MF_CHECKED : MF_UNCHECKED); + + int prio = g_config->ReadInt(L"extractprio", THREAD_PRIORITY_NORMAL); + CheckMenuItem(menu, ID_RIPOPTIONS_PRIORITY_IDLE, prio == THREAD_PRIORITY_IDLE ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_PRIORITY_LOWEST, prio == THREAD_PRIORITY_LOWEST ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_PRIORITY_BELOWNORMAL, prio == THREAD_PRIORITY_BELOW_NORMAL ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_PRIORITY_NORMAL, prio == THREAD_PRIORITY_NORMAL ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_PRIORITY_ABOVENORMAL, prio == THREAD_PRIORITY_ABOVE_NORMAL ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, ID_RIPOPTIONS_PRIORITY_HIGH, prio == THREAD_PRIORITY_HIGHEST ? MF_CHECKED : MF_UNCHECKED); + + int x = Menu_TrackPopup(plugin.hwndLibraryParent, menu, + TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_BOTTOMALIGN | + TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RETURNCMD, + r.left, r.top, hwndDlg, NULL); + switch (x) + { + case ID_RIPOPTIONS_RIPPINGSTATUSWINDOW: + { + int x = g_config->ReadInt(L"cdripstatuswnd", 0); + g_config->WriteInt(L"cdripstatuswnd", !x); + ShowWindow(m_extract_wnd, x ? SW_HIDE : SW_SHOW); + } + break; + case ID_RIPOPTIONS_EJECTCDWHENCOMPLETED: + g_config->WriteInt(L"cdripautoeject", !g_config->ReadInt(L"cdripautoeject", 0)); + break; + case ID_RIPOPTIONS_PLAYTRACKSWHENCOMPLETED: + g_config->WriteInt(L"cdripautoplay", !g_config->ReadInt(L"cdripautoplay", 0)); + break; + case ID_RIPOPTIONS_CLOSEVIEWWHENCOMPLETE: + g_config->WriteInt(L"cdripautoclose", !g_config->ReadInt(L"cdripautoclose", 0)); + break; + case ID_RIPOPTIONS_PRIORITY_IDLE: + case ID_RIPOPTIONS_PRIORITY_LOWEST: + case ID_RIPOPTIONS_PRIORITY_BELOWNORMAL: + case ID_RIPOPTIONS_PRIORITY_NORMAL: + case ID_RIPOPTIONS_PRIORITY_ABOVENORMAL: + case ID_RIPOPTIONS_PRIORITY_HIGH: + { + int prio = THREAD_PRIORITY_NORMAL; + if (x == ID_RIPOPTIONS_PRIORITY_IDLE) prio = THREAD_PRIORITY_IDLE; + if (x == ID_RIPOPTIONS_PRIORITY_LOWEST) prio = THREAD_PRIORITY_LOWEST; + if (x == ID_RIPOPTIONS_PRIORITY_BELOWNORMAL) prio = THREAD_PRIORITY_BELOW_NORMAL; + if (x == ID_RIPOPTIONS_PRIORITY_ABOVENORMAL) prio = THREAD_PRIORITY_ABOVE_NORMAL; + if (x == ID_RIPOPTIONS_PRIORITY_HIGH) prio = THREAD_PRIORITY_HIGHEST; + g_config->WriteInt(L"extractprio", prio); + convertSetPriorityW csp = { + &m_fcs, + prio, + }; + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&csp, IPC_CONVERT_SET_PRIORITYW); + } + break; + } + Sleep(100); + MSG msg; + while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); //eat return + } + return 0; + case IDC_CANCEL_RIP: + { + wchar_t title[64] = {0}; + if (!m_extract_wnd || + m_rip_done || + MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_CANCEL_RIP), + WASABI_API_LNGSTRINGW_BUF(IDS_CD_RIP_QUESTION,title,64), + MB_YESNO | MB_ICONQUESTION) == IDYES) + { + if (m_rip_params) LockCD(m_rip_params->drive_letter, FALSE); + if (m_extract_wnd) DestroyWindow(m_extract_wnd); + DestroyWindow(hwndDlg); + } + return 0; + } + case IDC_BTN_SHOWINFO: + switch(HIWORD(wParam)) + { + case BN_CLICKED: + SendMessageW(GetParent(hwndDlg), WM_COMMAND, wParam, lParam); + NotifyInfoWindow(hwndDlg, TRUE); + break; + } + break; + } + break; + case WM_DESTROY: + if (m_statuslist.getwnd()) + { + g_view_metaconf->WriteInt(L"col_track", m_statuslist.GetColumnWidth(0)); + g_view_metaconf->WriteInt(L"col_title", m_statuslist.GetColumnWidth(1)); + g_view_metaconf->WriteInt(L"col_len", m_statuslist.GetColumnWidth(2)); + g_view_metaconf->WriteInt(L"col_status", m_statuslist.GetColumnWidth(3)); + } + + m_hwndstatus = 0; + return 0; + + case WM_ERASEBKGND: return 1; //handled by WADlg_DrawChildWindowBorders in WM_PAINT + case WM_QUERYFILEINFO: Window_OnQueryInfo(hwndDlg); break; + case WM_NOTIFY: return Window_OnNotify(hwndDlg, (INT)wParam, (LPNMHDR) lParam); + + + } + return 0; +} + +static BOOL CALLBACK extract_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + m_extract_wnd = hwndDlg; + m_rip_done = 0; + SetDlgItemText(hwndDlg, IDC_STATUS, WASABI_API_LNGSTRINGW(IDS_INITIALIZING)); + m_pstat_bytesdone = 0; + m_pstat_bytesout = 0; + m_pstat_timedone = 0; + m_extract_nb = 0; + m_extract_curtrack = -1; + m_cur_rg = 0; + { + m_extract_nb_total = 0; + int l = m_rip_params->ntracks; + for (int i = 0;i < l;i++) if (m_rip_params->tracks[i]) m_extract_nb_total++; + } + + LockCD(m_rip_params->drive_letter, TRUE); + + SetPropW(hwndDlg, L"WARIPPER", (HANDLE)hwndDlg); + SetPropW(hwndDlg, L"DRIVE", (HANDLE)(INT_PTR)(0xFF & m_rip_params->drive_letter)); + + if (!uMsgRipperNotify) uMsgRipperNotify = RegisterWindowMessageA("WARIPPER_BROADCAST_MSG"); + if (uMsgRipperNotify) SendNotifyMessage(HWND_BROADCAST, uMsgRipperNotify, (WPARAM)m_rip_params->drive_letter, (LPARAM)TRUE); + SendDlgItemMessage(hwndDlg, IDC_PROGRESS1, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + SendDlgItemMessage(hwndDlg, IDC_PROGRESS2, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + PostMessage(hwndDlg, WM_APP + 1, 0, 0); + if (g_config->ReadInt(L"cdripstatuswnd", 0)) ShowWindow(hwndDlg, SW_SHOW); + + INT bVal; + + if (S_OK == Settings_GetBool(C_EXTRACT, EF_CALCULATERG, &bVal) && bVal) + { + CreateGain(); + QueueUserAPC(StartGain, rgThread, + (ULONG_PTR)((m_rip_params->ntracks == m_extract_nb_total) ? RG_ALBUM : RG_INDIVIDUAL_TRACKS)); + } + break; + case WM_APP + 2: // track is starting to be RG scanned + m_statuslist.SetItemText(m_cur_rg, 3, WASABI_API_LNGSTRINGW(IDS_CALCULATING_REPLAY_GAIN)); + break; + case WM_APP + 3: // track is starting to be RG scanned + m_statuslist.SetItemText(m_cur_rg, 3, WASABI_API_LNGSTRINGW(IDS_COMPLETED)); + m_cur_rg++; + break; + case WM_APP + 1: + { + INT trackOffset, cchDest; + TCHAR szDestination[MAX_PATH] = {0}, szFormat[MAX_PATH] = {0}; + int l = m_rip_params->ntracks; + done = 1; + + Settings_GetInt(C_EXTRACT, EF_TRACKOFFSET, &trackOffset); + Settings_ReadString(C_EXTRACT, EF_TITLEFMT, szFormat, ARRAYSIZE(szFormat)); + Settings_ReadString(C_EXTRACT, EF_PATH, szDestination, ARRAYSIZE(szDestination)); + CleanupDirectoryString(szDestination); + + cchDest = lstrlen(szDestination); + + for (int i = m_extract_curtrack + 1;i < l;i++) + { + if (m_rip_params->tracks[i]) + { + StringCchPrintfW(m_extract_src, 64, L"cda://%c,%d.cda", m_rip_params->drive_letter, i + 1); + szDestination[cchDest] = TEXT('\0'); + if (cchDest) PathAddBackslash(szDestination); + + wchar_t tmp1[32] = {0}, tmp2[32] = {0}, tmp3[32] = {0}, tmp4[32] = {0}, tmp5[32] = {0}; + FormatFileName(szDestination, + ARRAYSIZE(szDestination)-11, // ensure we're leaving enough room for the extension + szFormat, + i + trackOffset, + (m_rip_params->artist && *(m_rip_params->artist)) ? (m_rip_params->artist) : WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN_ARTIST,tmp1,32), + (m_rip_params->album && *(m_rip_params->album)) ? (m_rip_params->album) : WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN_ALBUM,tmp2,32), + (m_rip_params->tracks[i] && *(m_rip_params->tracks[i])) ? (m_rip_params->tracks[i]) : L"0", + (m_rip_params->genre && *(m_rip_params->genre)) ? (m_rip_params->genre) : WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN,tmp3,32), + (m_rip_params->year && *(m_rip_params->year)) ? (m_rip_params->year) : WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN,tmp4,32), + (m_rip_params->trackArtists[i] && m_rip_params->trackArtists[i][0])?m_rip_params->trackArtists[i] : WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN,tmp5,32), + NULL, (m_rip_params->disc && *(m_rip_params->disc)) ? (m_rip_params->disc) : L""); + memset(&m_fcs, 0, sizeof(m_fcs)); + m_fcs.sourcefile = m_extract_src; + INT fourcc; + Settings_GetInt(C_EXTRACT, EF_FOURCC, &fourcc); + m_fcs.destformat[0]=fourcc; + if (m_fcs.destformat[0] == OLD_AAC_CODEC) Settings_GetDefault(C_EXTRACT, EF_FOURCC, &m_fcs.destformat[0]); + + // now determine the extension + wchar_t fmt[10] = {0}; + GetExtensionString(fmt, ARRAYSIZE(fmt), (DWORD)m_fcs.destformat[0]); + BOOL upperCase; + if (SUCCEEDED(Settings_GetBool(C_EXTRACT, EF_UPPEREXTENSION, &upperCase)) && FALSE != upperCase) + CharUpper(fmt); + else + CharLower(fmt); + + StringCchCat(szDestination, ARRAYSIZE(szDestination), TEXT(".")); + StringCchCat(szDestination, ARRAYSIZE(szDestination), fmt); + + if (m_rip_params->filenames[i]) free(m_rip_params->filenames[i]); + m_rip_params->filenames[i] = _wcsdup(szDestination); + + wchar_t tempFile[MAX_PATH] = {0}; + wchar_t tmppath[MAX_PATH] = {0}; + GetTempPath(MAX_PATH,tmppath); + GetTempFileName(tmppath,L"rip",0,tempFile); + + m_rip_params->tempFilenames[i] = _wcsdup(tempFile); + createDirForFileW(m_rip_params->filenames[i]); + m_fcs.destfile = _wcsdup(tempFile); + createDirForFileW(m_fcs.destfile); + m_fcs.callbackhwnd = hwndDlg; + m_fcs.error = L""; + m_extract_time = 0; + m_extract_curtrack = i; + + wchar_t *ptr = m_rip_params->filenames[i]; + if (cchDest && cchDest < (int)lstrlenW(ptr)) ptr += (cchDest + 1); + SetDlgItemText(hwndDlg, IDC_CURTRACK, ptr); + + if (SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&m_fcs, IPC_CONVERTFILEW) != 1) + { + wchar_t tmp[512] = {0}; + StringCchPrintf(tmp, 512, WASABI_API_LNGSTRINGW(IDS_ERROR_RIPPING_TRACK), i + 1, m_fcs.error ? m_fcs.error : L""); + MessageBox(hwndDlg, tmp, WASABI_API_LNGSTRINGW(IDS_ERROR), MB_OK); + done = -1; + break; + } + convertSetPriorityW csp = { + &m_fcs, + g_config->ReadInt(L"extractprio", THREAD_PRIORITY_NORMAL), + }; + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&csp, IPC_CONVERT_SET_PRIORITYW); + m_extracting = 1; + done = 0; + PostMessage(hwndDlg, WM_WA_IPC , 0, IPC_CB_CONVERT_STATUS); + break; + } + } + if (done && m_rip_params) + { + LockCD(m_rip_params->drive_letter, FALSE); + + if (g_config->ReadInt(L"cdripautoeject", 0) && done > 0) + { + char buf[64] = {0}; + StringCchPrintfA(buf, 64, "cda://%c.cda", m_rip_params->drive_letter); + char buf2[32] = {0}; + getFileInfo(buf, "<eject>", buf2, sizeof(buf2)); + } + + if (g_config->ReadInt(L"cdripautoplay", 0) && done > 0) + { + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_DELETE); + for (int i = 0;i < m_rip_params->ntracks;i++) + { + if (m_rip_params->tracks[i]) + { + COPYDATASTRUCT cds; + cds.dwData = IPC_PLAYFILEW; + cds.lpData = (void *) m_rip_params->filenames[i]; + cds.cbData = sizeof(wchar_t) * (lstrlenW(m_rip_params->filenames[i]) + 1); // include space for null char + SendMessage(plugin.hwndWinampParent, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds); + } + } + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_STARTPLAY); + } + + + if (m_rip_params->ntracks == m_extract_nb_total && done > 0) + { + INT bVal; + if ((S_OK == Settings_GetBool(C_EXTRACT, EF_CREATEM3U, &bVal) && bVal) || + (S_OK == Settings_GetBool(C_EXTRACT, EF_CREATEPLS, &bVal) && bVal)) + { + + wchar_t str[MAX_PATH] = {0}, fmt[MAX_PATH] = {0}; + Settings_ReadString(C_EXTRACT, EF_PLAYLISTFMT, fmt, ARRAYSIZE(fmt)); + Settings_ReadString(C_EXTRACT, EF_PATH, str, ARRAYSIZE(str)); + + int l = lstrlenW(str); + if (l) + PathAddBackslash(str); + + FormatFileName(str, ARRAYSIZE(str)-5, // ensure we're leaving enough room for the extension + fmt, 0xdeadbeef, + m_rip_params->artist ? m_rip_params->artist : L"", + m_rip_params->album ? m_rip_params->album : L"", + NULL, + m_rip_params->genre ? m_rip_params->genre : L"", + m_rip_params->year ? m_rip_params->year : L"", + NULL, + NULL, + m_rip_params->disc ? m_rip_params->disc : L""); + + if (S_OK == Settings_GetBool(C_EXTRACT, EF_CREATEM3U, &bVal) && bVal) + { + wchar_t str2[MAX_PATH] = {0}; + lstrcpynW(str2, str, MAX_PATH); + StringCchCatW(str2, MAX_PATH, L".m3u"); + createDirForFileW(str2); + M3UWriter w; + FILE *fp=_wfopen(str2, L"wt"); + w.Open(fp, AutoCharFn(str2), TRUE); + BOOL ext; + Settings_GetBool(C_EXTRACT, EF_USEM3UEXT, &ext); + for (int i = 0;i < m_rip_params->ntracks;i++) + { + if (m_rip_params->tracks[i] && m_rip_params->filenames[i]) + { + GayString str; + str.Set(AutoChar(m_rip_params->artist)); + str.Append(" - "); + str.Append(AutoChar(m_rip_params->tracks[i])); + if (ext) + w.SetExtended(AutoCharFn(m_rip_params->filenames[i]), str.Get(), m_rip_params->lengths[i]); + else + w.SetFilename(AutoCharFn(m_rip_params->filenames[i])); + + } + } + w.Close(); + } + + if (S_OK == Settings_GetBool(C_EXTRACT, EF_CREATEPLS, &bVal) && bVal) + { + char str2[MAX_PATH] = {0}; + lstrcpynA(str2, AutoChar(str), MAX_PATH); + StringCchCatA(str2, MAX_PATH, ".pls"); + createDirForFile(str2); + // TODO: check for bad unicode conversion + PLSWriter w; + w.Open(str2); + for (int i = 0;i < m_rip_params->ntracks;i++) + { + if (m_rip_params->tracks[i] && m_rip_params->filenames[i]) + { + GayString str; + str.Set(AutoChar(m_rip_params->artist)); + str.Append(" - "); + str.Append(AutoChar(m_rip_params->tracks[i])); + w.SetFilename(AutoCharFn(m_rip_params->filenames[i])); + w.SetTitle(str.Get()); + w.SetLength(m_rip_params->lengths[i]); + w.Next(); + } + } + w.Close(); + } + } + + if (S_OK == Settings_GetBool(C_EXTRACT, EF_CREATEMLPL, &bVal) && bVal) + { + itemRecordListW irl = {0, }; + allocRecordList(&irl, m_rip_params->ntracks, 0); + for (int i = 0;i < m_rip_params->ntracks;i++) + { + if (m_rip_params->tracks[i]) + { + int n = irl.Size; + memset(&irl.Items[n], 0, sizeof(itemRecordW)); + irl.Items[n].filename = _wcsdup(m_rip_params->filenames[i]); + irl.Items[n].album = _wcsdup(m_rip_params->album); + irl.Items[n].artist = _wcsdup(m_rip_params->artist); + irl.Items[n].title = _wcsdup(m_rip_params->tracks[i]); + irl.Items[n].genre = _wcsdup(m_rip_params->genre); + irl.Items[n].year = _wtoi(m_rip_params->year); + irl.Items[n].length = m_rip_params->lengths[i]; + irl.Size++; + } + } + + GayString str; + str.Set(AutoChar(m_rip_params->artist)); + str.Append(" - "); + str.Append(AutoChar(m_rip_params->album)); + AutoWide name(str.Get()); + mlMakePlaylist pl = {sizeof(mlMakePlaylist), (const wchar_t*)name, ML_TYPE_ITEMRECORDLISTW, (void *) & irl, 0x01}; + SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&pl, ML_IPC_PLAYLIST_MAKE); + freeRecordList(&irl); + } + } // playlist creation + + if (rgThread) + QueueUserAPC(WriteGain, rgThread, 0); + else + PostMessage(m_extract_wnd, WM_APP + 4, 0, 0); + } + } + break; + case WM_APP + 4: + if (m_db_has_upd) + { + // TODO: benski> does mldb read metadata from this call or the 'add' call - because it won't have replaygain tags until now + PostMessage(plugin.hwndLibraryParent, WM_ML_IPC, 0, ML_IPC_DB_SYNCDB); + } + + m_rip_done = 1; + if (g_config->ReadInt(L"cdripautoclose", 1)) + { + DestroyWindow(hwndDlg); + } + else + { + SetWindowText(hwndDlg, WASABI_API_LNGSTRINGW(done > 0 ? IDS_RIP_COMPLETE : IDS_RIP_FAILED)); + SetDlgItemText(hwndDlg, IDC_BUTTON1, WASABI_API_LNGSTRINGW(IDS_CLOSE)); + if (m_hwndstatus) + { + SetDlgItemText(m_hwndstatus, IDC_CANCEL_RIP, WASABI_API_LNGSTRINGW(IDS_CLOSE)); + } + SendDlgItemMessage(hwndDlg, IDC_PROGRESS1, PBM_SETPOS, 100, 0); + SendDlgItemMessage(hwndDlg, IDC_PROGRESS2, PBM_SETPOS, 100, 0); + + + int now = m_pstat_timedone; + + int bytesout = m_pstat_bytesout; + + double extracted_time = (double) m_pstat_bytesdone * (1.0 / 44100.0 / 4.0); + if (extracted_time < 1.0) extracted_time = 1.0; + + int br = (int) (((double)bytesout * 8.0 / extracted_time) / 1000.0 + 0.5); + + if (done > 0) + { + wchar_t sstr[16] = {0}; + StringCchPrintf(m_last_total_status, 512, + WASABI_API_LNGSTRINGW(IDS_X_TRACKS_RIPPED_IN_X), + m_extract_nb_total, + WASABI_API_LNGSTRINGW_BUF(m_extract_nb_total == 1 ? IDS_TRACK : IDS_TRACKS,sstr,16), + now / 1000 / 60, (now / 1000) % 60, + extracted_time / (now / 1000.0), + br, (double)bytesout * (1.0 / (1024.0*1024.0)) + ); + } + else + { + WASABI_API_LNGSTRINGW_BUF(IDS_RIP_FAILED,m_last_total_status,512); + } + + SetDlgItemText(hwndDlg, IDC_STATUS2, m_last_total_status); + SetDlgItemText(hwndDlg, IDC_CURTRACK, WASABI_API_LNGSTRINGW(IDS_COMPLETED)); + SetDlgItemText(hwndDlg, IDC_STATUS, L""); + + if (m_hwndstatus && IsWindow(m_hwndstatus)) + { + SetDlgItemText(m_hwndstatus, IDC_CDINFO, m_last_total_status); + SetDlgItemText(m_hwndstatus, IDC_CANCEL_RIP, WASABI_API_LNGSTRINGW(IDS_DONE)); + } + } + break; + case WM_WA_IPC: + switch (lParam) + { + case IPC_CB_CONVERT_STATUS: + { + if (!m_extract_time) + { + m_extract_time = GetTickCount(); + break; + } + DWORD now = GetTickCount() - m_extract_time; + if (!now) now = 1000; //safety + wchar_t tmp[512 + 128] = {0}; + + { + int total_t = 0; + if (wParam) total_t = MulDiv(100, now, (int)wParam); + int rem_t = total_t - now; + + double extracted_time = (double) m_fcs.bytes_done * (1.0 / 44100.0 / 4.0); + if (extracted_time < 1.0) extracted_time = 1.0; + int br = (int) (((double)m_fcs.bytes_out * 8.0 / extracted_time) / 1000.0 + 0.5); + + int estsize = 0; + if (m_fcs.bytes_total > 0) estsize = MulDiv(m_fcs.bytes_out, m_fcs.bytes_total, m_fcs.bytes_done); + + if (rem_t < 0) rem_t = 0; + if (total_t < 0) total_t = 0; + + StringCchPrintf(tmp, 640, + WASABI_API_LNGSTRINGW(IDS_ELAPSED_X_REMAINING_X_TOTAL_X), + now / 1000 / 60, (now / 1000) % 60, + rem_t / 1000 / 60, (rem_t / 1000) % 60, + total_t / 1000 / 60, (total_t / 1000) % 60, + extracted_time / ((double)now / 1000.0), + br, (double)estsize * (1.0 / (1024.0*1024.0)) + ); + SetDlgItemText(hwndDlg, IDC_STATUS, tmp); + + if (m_hwndstatus && IsWindow(m_hwndstatus)) + { + StringCchPrintf(m_last_item_status, 512, + WASABI_API_LNGSTRINGW(IDS_X_KBPS_AT_X_REALTIME), + wParam, + br, + extracted_time / ((double)now / 1000.0) + ); + m_statuslist.SetItemText(m_extract_nb, 3, m_last_item_status); + } + } + + { + int total_in_bytes_calc = m_rip_params->total_length_bytes; + + now += m_pstat_timedone; + + int total_t = 0; + int bytesdone = m_fcs.bytes_done + m_pstat_bytesdone; + int bytesout = m_fcs.bytes_out + m_pstat_bytesout; + if (bytesdone) total_t = MulDiv(total_in_bytes_calc, now, bytesdone); + + int rem_t = total_t - now; + + double extracted_time = (double) bytesdone * (1.0 / 44100.0 / 4.0); + if (extracted_time < 1.0) extracted_time = 1.0; + int br = (int) (((double)bytesout * 8.0 / extracted_time) / 1000.0 + 0.5); + + int estsize = 0; + if (total_in_bytes_calc > 0) estsize = MulDiv(bytesout, total_in_bytes_calc, bytesdone); + + if (rem_t < 0) rem_t = 0; + if (total_t < 0) total_t = 0; + + StringCchPrintf(m_last_total_status, 512, + WASABI_API_LNGSTRINGW(IDS_X_OF_X_ELAPSED_X_REMAINING_X), + m_extract_nb + 1, m_extract_nb_total, + now / 1000 / 60, (now / 1000) % 60, + rem_t / 1000 / 60, (rem_t / 1000) % 60, + total_t / 1000 / 60, (total_t / 1000) % 60, + extracted_time / ((double)now / 1000.0), + br, (double)estsize * (1.0 / (1024.0*1024.0)) + ); + + if (m_hwndstatus && IsWindow(m_hwndstatus)) + { + SetDlgItemText(m_hwndstatus, IDC_CDINFO, m_last_total_status); + } + SetDlgItemText(hwndDlg, IDC_STATUS2, m_last_total_status); + + int a = 0; + if (total_in_bytes_calc) a = MulDiv(bytesdone, 100, total_in_bytes_calc); + SendDlgItemMessage(hwndDlg, IDC_PROGRESS2, PBM_SETPOS, a, 0); + + StringCchPrintf(tmp, 640, WASABI_API_LNGSTRINGW(IDS_X_PERCENT_RIPPING_FROM_CD), a); + SetWindowText(hwndDlg, tmp); + } + + SendDlgItemMessage(hwndDlg, IDC_PROGRESS1, PBM_SETPOS, wParam, 0); + } + break; + case IPC_CB_CONVERT_DONE: + + SendMessage(plugin.hwndWinampParent , WM_WA_IPC, (WPARAM)&m_fcs, IPC_CONVERTFILEW_END); + free(m_fcs.destfile); + m_pstat_bytesdone += m_fcs.bytes_done; + m_pstat_bytesout += m_fcs.bytes_out; + if (m_extract_time) m_pstat_timedone += GetTickCount() - m_extract_time; + + CopyFileW(m_rip_params->tempFilenames[m_extract_curtrack], m_rip_params->filenames[m_extract_curtrack], FALSE); + DeleteFileW(m_rip_params->tempFilenames[m_extract_curtrack]); + if (AGAVE_API_STATS) + { + AGAVE_API_STATS->IncrementStat(api_stats::RIP_COUNT); + AGAVE_API_STATS->SetStat(api_stats::RIP_FORMAT, m_fcs.destformat[0]); + } + wchar_t *lastfn = m_rip_params->filenames[m_extract_curtrack]; + + if (g_config->ReadInt(L"extracttag", 1)) + { + // add metadata to this file + if (updateFileInfoW(lastfn, L"title", m_rip_params->tracks[m_extract_curtrack])) + { + updateFileInfoW(lastfn, L"conductor", m_rip_params->conductors[m_extract_curtrack]); + updateFileInfoW(lastfn, L"composer", m_rip_params->composers[m_extract_curtrack]); + updateFileInfoW(lastfn, L"GracenoteFileID", m_rip_params->gracenoteFileIDs[m_extract_curtrack]); + updateFileInfoW(lastfn, L"GracenoteExtData", m_rip_params->gracenoteExtData[m_extract_curtrack]); + updateFileInfoW(lastfn, L"artist", m_rip_params->trackArtists[m_extract_curtrack]); + //if (lstrcmpiW(m_rip_params->trackArtists[m_extract_curtrack], m_rip_params->artist)) // only write albumartist if they're different + updateFileInfoW(lastfn, L"albumartist", m_rip_params->artist); + updateFileInfoW(lastfn, L"album", m_rip_params->album); + updateFileInfoW(lastfn, L"genre", m_rip_params->genre); + updateFileInfoW(lastfn, L"year", m_rip_params->year); + updateFileInfoW(lastfn, L"disc", m_rip_params->disc); + updateFileInfoW(lastfn, L"publisher", m_rip_params->publisher); + if (m_rip_params->comment && m_rip_params->comment[0]) + updateFileInfoW(lastfn, L"comment", m_rip_params->comment); + else + { + TCHAR szComment[8192] = {0}; + Settings_ReadString(C_EXTRACT, EF_COMMENTTEXT, szComment, ARRAYSIZE(szComment)); + updateFileInfoW(lastfn, L"comment", szComment); + } + + wchar_t buf[32] = {0}; + if (m_extract_curtrack >= 0) + { + if (g_config->ReadInt(L"total_tracks", 0)) + StringCchPrintfW(buf, 32, L"%d/%d", m_extract_curtrack + g_config->ReadInt(L"trackoffs", 1), m_rip_params->ntracks); + else + StringCchPrintfW(buf, 32, L"%d", m_extract_curtrack + g_config->ReadInt(L"trackoffs", 1)); + } + else buf[0] = 0; + updateFileInfoW(lastfn, L"track", buf); + + if (WASABI_API_APP) + updateFileInfoW(lastfn, L"tool", WASABI_API_APP->main_getVersionString()); + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_WRITE_EXTENDED_FILE_INFO); + } + } + + if (g_config->ReadInt(L"extractaddml", 1)) + { + LMDB_FILE_ADD_INFOW fi = {lastfn, -1, -1}; + SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_DB_ADDORUPDATEFILEW, (WPARAM)&fi); + m_db_has_upd = 1; + } + + if (m_hwndstatus && IsWindow(m_hwndstatus)) + { + m_statuslist.SetItemText(m_extract_nb, 3, WASABI_API_LNGSTRING(IDS_WAITING)); + } + + if (rgThread) + QueueUserAPC(CalculateGain, rgThread, (ULONG_PTR)_wcsdup(lastfn)); + else + PostMessage(m_extract_wnd, WM_APP + 3, 0, 0); + + + m_extract_nb++; + m_extracting = 0; + PostMessage(hwndDlg, WM_APP + 1, 0, 0); + break; + } + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_BUTTON1: + { + wchar_t title[64] = {0}; + if (m_rip_done || + MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_CANCEL_RIP), + WASABI_API_LNGSTRINGW_BUF(IDS_CD_RIP_QUESTION,title,64), + MB_YESNO | MB_ICONQUESTION) == IDYES) + { + LockCD(m_rip_params->drive_letter, FALSE); + DestroyWindow(hwndDlg); + } + return 0; + } + case IDCANCEL: + g_config->WriteInt(L"cdripstatuswnd", 0); + ShowWindow(hwndDlg, SW_HIDE); + break; + } + break; + case WM_CLOSE: + return 0; + case WM_DESTROY: + if (m_extracting) + { + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&m_fcs, IPC_CONVERTFILEW_END); + // make sure we clean up on cancel! + m_extracting = 0; + DeleteFileW(m_rip_params->tempFilenames[m_extract_curtrack]); + } + if (uMsgRipperNotify) SendNotifyMessage(HWND_BROADCAST, uMsgRipperNotify, (WPARAM)(m_rip_params) ? m_rip_params->drive_letter : 0, (LPARAM)FALSE); + if (m_rip_params) + { + int i; + for (i = 0; i < m_rip_params->ntracks; i++) + { + free(m_rip_params->tracks[i]); + free(m_rip_params->trackArtists[i]); + free(m_rip_params->composers[i]); + free(m_rip_params->gracenoteFileIDs[i]); + free(m_rip_params->gracenoteExtData[i]); + free(m_rip_params->conductors[i]); + free(m_rip_params->filenames[i]); + free(m_rip_params->tempFilenames[i]); + } + free(m_rip_params->gracenoteFileIDs); + free(m_rip_params->gracenoteExtData); + free(m_rip_params->composers); + free(m_rip_params->conductors); + free(m_rip_params->tracks); + free(m_rip_params->trackArtists); + free(m_rip_params->filenames); + free(m_rip_params->tempFilenames); + free(m_rip_params->lengths); + + free(m_rip_params->album); + free(m_rip_params->artist); + free(m_rip_params->genre); + free(m_rip_params->year); + free(m_rip_params->publisher); + free(m_rip_params->comment); + free(m_rip_params->disc); + + free(m_rip_params); + m_rip_params = 0; + } + m_extract_wnd = 0; + + if (rgThread) + QueueUserAPC(CloseGain, rgThread, 0); + + break; + } + return 0; +} + +void cdrip_stop_all_extracts() +{ + if (m_rip_params) LockCD(m_rip_params->drive_letter, FALSE); + if (m_extract_wnd) DestroyWindow(m_extract_wnd); + if (m_hwndstatus) DestroyWindow(m_hwndstatus); +} + +int cdrip_isextracting(char drive) +{ + if (!m_rip_params) return 0; + if (drive == -1 && m_rip_done) + { + if (m_extract_wnd && IsWindow(m_extract_wnd)) DestroyWindow(m_extract_wnd); + if (m_hwndstatus && IsWindow(m_hwndstatus)) DestroyWindow(m_hwndstatus); + return 0; + } + if (drive == 0 || drive == -1) return toupper(m_rip_params->drive_letter); + return toupper(m_rip_params->drive_letter) == toupper(drive); +} + +HWND cdrip_FindBurningHWND(char cLetter) +{ + HWND h = 0; + while (NULL != (h = FindWindowExW(NULL, h, L"#32770", NULL))) + { + if (!GetPropW(h, L"WARIPPER")) continue; + if (((char)(INT_PTR)GetPropW(h, L"DRIVE")) == cLetter) return h; + } + return NULL; +} + +void cdrip_extractFiles(cdrip_params *parms) +{ + WASABI_API_LNGSTRINGW_BUF(IDS_INITIALIZING,m_last_total_status,512); + m_last_item_status[0] = 0; + m_rip_params = parms; + WASABI_API_CREATEDIALOGW(IDD_VIEW_CDROM_EXTRACT, plugin.hwndWinampParent, extract_dialogProc); +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/cmdbar_data.cpp b/Src/Plugins/Library/ml_disc/cmdbar_data.cpp new file mode 100644 index 00000000..1cd8b511 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/cmdbar_data.cpp @@ -0,0 +1,485 @@ +#include "main.h" +#include <windowsx.h> +#include "./resource.h" +#include "./commandbar.h" +#include <shlwapi.h> +#include <strsafe.h> + +static HMLIMGLST hmlilButton = NULL; + +static LPCTSTR GetImageTagStr(INT resId) +{ + switch(resId) + { + case IDB_PLAY_NORMAL: return TEXT("button.play"); + case IDB_PLAY_HIGHLIGHTED: return TEXT("button.play.highlighted"); + case IDB_PLAY_PRESSED: return TEXT("button.play.pressed"); + case IDB_PLAY_DISABLED: return TEXT("button.play.disabled"); + case IDB_ENQUEUE_NORMAL: return TEXT("button.enqueue"); + case IDB_ENQUEUE_HIGHLIGHTED: return TEXT("button.enqueue.highlighted"); + case IDB_ENQUEUE_PRESSED: return TEXT("button.enqueue.pressed"); + case IDB_ENQUEUE_DISABLED: return TEXT("button.enqueue.disabled"); + case IDB_EJECT2_NORMAL: return TEXT("button.eject"); + case IDB_EJECT2_HIGHLIGHTED: return TEXT("button.eject.highlighted"); + case IDB_EJECT2_PRESSED: return TEXT("button.eject.pressed"); + case IDB_EJECT2_DISABLED: return TEXT("button.eject.disabled"); + } + return NULL; +} + +static HMLIMGLST DataCmdBar_CreateImageList() +{ + HMLIMGLST hmlil; + MLIMAGELISTCREATE mlilCreate; + MLIMAGESOURCE mlis; + MLIMAGELISTITEM mlilItem; + + mlilCreate.cx = g_view_metaconf->ReadIntEx(TEXT("artwork"), TEXT("button.icon.cx"), 12); + mlilCreate.cy = g_view_metaconf->ReadIntEx(TEXT("artwork"), TEXT("button.icon.cy"), 12); + mlilCreate.cInitial = 12; + mlilCreate.cGrow = 3; + mlilCreate.cCacheSize = 4; + mlilCreate.flags = MLILC_COLOR32; + + hmlil = MLImageList_Create(plugin.hwndLibraryParent, &mlilCreate); + if (NULL == hmlil) return NULL; + + + ZeroMemory(&mlilItem, sizeof(MLIMAGELISTITEM)); + mlilItem.cbSize = sizeof(MLIMAGELISTITEM); + mlilItem.hmlil = hmlil; + mlilItem.filterUID = MLIF_BUTTONBLENDPLUSCOLOR_UID; + mlilItem.pmlImgSource = &mlis; + + ZeroMemory(&mlis, sizeof(MLIMAGESOURCE)); + mlis.cbSize = sizeof(MLIMAGESOURCE); + mlis.type = SRC_TYPE_PNG; + mlis.hInst = plugin.hDllInstance; + + + INT imageList[] = + { IDB_PLAY_NORMAL, IDB_PLAY_PRESSED, IDB_PLAY_HIGHLIGHTED, IDB_PLAY_DISABLED, + IDB_ENQUEUE_NORMAL, IDB_ENQUEUE_PRESSED, IDB_ENQUEUE_HIGHLIGHTED, IDB_ENQUEUE_DISABLED, + IDB_EJECT2_NORMAL, IDB_EJECT2_PRESSED, IDB_EJECT2_HIGHLIGHTED, IDB_EJECT2_DISABLED, + }; + + + TCHAR szResource[MAX_PATH] = {0}, szPath[MAX_PATH] = {0}, szFullPath[MAX_PATH] = {0}; + g_view_metaconf->ReadCchStringEx(szPath, ARRAYSIZE(szPath), TEXT("artwork"), TEXT("path"), NULL); + for(int i = 0; i < sizeof(imageList)/sizeof(imageList[0]); i++) + { + mlilItem.nTag = imageList[i]; + g_view_metaconf->ReadCchStringEx(szResource, ARRAYSIZE(szResource), TEXT("artwork"), GetImageTagStr(imageList[i]), NULL); + if (TEXT('\0') != szResource[0]) + { + PathCombine(szFullPath, szPath, szResource); + mlis.lpszName = szFullPath; + mlis.flags |= ISF_LOADFROMFILE; + } + else + { + mlis.lpszName = MAKEINTRESOURCE(imageList[i]); + mlis.flags &= ~ISF_LOADFROMFILE; + } + + MLImageList_Add(plugin.hwndLibraryParent, &mlilItem); + } + return hmlil; +} + +static HMLIMGLST DataCmdBar_CreateDropDownImageList(HMENU hMenu) +{ + HMLIMGLST hmlil; + MLIMAGELISTCREATE mlilCreate; + MLIMAGESOURCE mlis; + + if (!hMenu) return NULL; + + mlilCreate.cx = 16; + mlilCreate.cy = 16; + mlilCreate.cInitial = 2; + mlilCreate.cGrow = 1; + mlilCreate.cCacheSize = 3; + mlilCreate.flags = MLILC_COLOR32; + + hmlil = MLImageList_Create(plugin.hwndLibraryParent, &mlilCreate); + if (NULL == hmlil) return NULL; + + ZeroMemory(&mlis, sizeof(MLIMAGESOURCE)); + mlis.cbSize = sizeof(MLIMAGESOURCE); + mlis.type = SRC_TYPE_PNG; + mlis.hInst = plugin.hDllInstance; + + + INT imageList[] = { IDB_PLAY_MENU, IDB_ENQUEUE_MENU, }; + MENUITEMINFOW mii = { sizeof(MENUITEMINFOW), }; + mii.fMask = MIIM_ID; + for(int i = 0; i < sizeof(imageList)/sizeof(imageList[0]); i++) + { + if (GetMenuItemInfoW(hMenu, i, TRUE, &mii)) + { + mlis.lpszName = MAKEINTRESOURCEW(imageList[i]); + MLImageList_Add2(plugin.hwndLibraryParent, hmlil, MLIF_FILTER1_UID, &mlis, mii.wID); + } + } + return hmlil; + +} + + + +static void DataCmdBar_SetButtonImages(HWND hButton, HMLIMGLST hmlil, INT normal, INT hover, INT pressed, INT disabled) +{ + MLBUTTONIMAGELIST bil; + MLIMAGELISTTAG t; + bil.hmlil = hmlil; + t.hmlil = bil.hmlil; + + t.nTag = normal; + bil.normalIndex = (MLImageList_GetIndexFromTag(plugin.hwndLibraryParent, &t)) ? t.mlilIndex : -1; + + if (disabled == normal) bil.disabledIndex = bil.normalIndex; + else + { + t.nTag = disabled; + bil.disabledIndex = (MLImageList_GetIndexFromTag(plugin.hwndLibraryParent, &t)) ? t.mlilIndex : bil.normalIndex; + } + + if (hover == normal) bil.hoverIndex = bil.normalIndex; + else if (hover == disabled) bil.hoverIndex = bil.disabledIndex; + else + { + t.nTag = hover; + bil.hoverIndex = (MLImageList_GetIndexFromTag(plugin.hwndLibraryParent, &t)) ? t.mlilIndex : bil.normalIndex; + } + + if (pressed == normal) bil.pressedIndex = bil.normalIndex; + else if (pressed == disabled) bil.pressedIndex = bil.disabledIndex; + else if (pressed == hover) bil.pressedIndex = bil.hoverIndex; + else + { + t.nTag = pressed; + bil.pressedIndex = (MLImageList_GetIndexFromTag(plugin.hwndLibraryParent, &t)) ? t.mlilIndex : bil.normalIndex; + } + + SENDMLIPC(hButton, ML_IPC_SKINNEDBUTTON_SETIMAGELIST, (LPARAM)&bil); +} + +static void PlayEx_Initialize(HWND hdlg) +{ + HWND hButton = GetDlgItem(hdlg, IDC_BTN_PLAYEX); + if (!hButton) return; + + HWND hFileView = (HWND)CommandBar_GetData(hdlg); + if (NULL == hFileView) return; + + HMENU hMenu = FileView_GetMenu(hFileView, FVMENU_PLAY); + if (!hMenu) return; + + BOOL bPlay = (!hFileView || 0 == (FVS_ENQUEUE & FileView_GetStyle(hFileView))); + + WCHAR szBuffer[256] = {0}; + MENUITEMINFOW mii = { sizeof(MENUITEMINFOW), }; + mii.fMask = MIIM_STRING; + mii.dwTypeData = szBuffer; + mii.cch = sizeof(szBuffer)/sizeof(szBuffer[0]); + if (GetMenuItemInfoW(hMenu, (bPlay) ? 0 : 1, TRUE, &mii)) + { + while(mii.cch && L'\t' != szBuffer[mii.cch]) mii.cch--; + if (mii.cch > 0) szBuffer[mii.cch] = L'\0'; + SetWindowTextW(hButton, szBuffer); + } + + if (bPlay) + { + DataCmdBar_SetButtonImages(hButton, hmlilButton, IDB_PLAY_NORMAL, + IDB_PLAY_PRESSED, IDB_PLAY_HIGHLIGHTED, IDB_PLAY_DISABLED); + } + else + { + DataCmdBar_SetButtonImages(hButton, hmlilButton, IDB_ENQUEUE_NORMAL, + IDB_ENQUEUE_PRESSED, IDB_ENQUEUE_HIGHLIGHTED, IDB_ENQUEUE_DISABLED); + } +} + +static void DataCmdBar_UpdateControls(HWND hdlg, BOOL bRedraw) +{ + INT buttonList[] = { IDC_BTN_PLAYEX, IDC_BTN_COPY, }; + HDWP hdwp; + DWORD flags, size; + INT w; + + flags = SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | ((bRedraw) ? 0 : SWP_NOREDRAW); + hdwp = BeginDeferWindowPos(sizeof(buttonList)/sizeof(buttonList[0])); + if (!hdwp) return; + + for(int i =0; i < sizeof(buttonList)/sizeof(buttonList[0]); i++) + { + HWND hctrl = GetDlgItem(hdlg, buttonList[i]); + if (NULL != hctrl) + { + size = 0; + switch(buttonList[i]) + { + case IDC_BTN_PLAYEX: + { + HWND hFileView = (HWND)CommandBar_GetData(hdlg); + if (NULL == hFileView) return; + + HMENU hMenu = FileView_GetMenu(hFileView, FVMENU_PLAY); + if (hMenu) + { + WCHAR szText[256] = {0}; + INT count = GetMenuItemCount(hMenu); + MENUITEMINFO mii = {0}; + + mii.cbSize = sizeof(MENUITEMINFO); + mii.fMask = MIIM_STRING; + mii.dwTypeData = szText; + + w = 0; + for (int i = 0; i < count; i++) + { + mii.cch = sizeof(szText)/sizeof(szText[0]); + if (GetMenuItemInfo(hMenu, i, TRUE, &mii)) + { + while(mii.cch && L'\t' != szText[mii.cch]) mii.cch--; + if (mii.cch > 0) szText[mii.cch] = L'\0'; + size = MLSkinnedButton_GetIdealSize(hctrl, szText); + if (w < LOWORD(size)) w = LOWORD(size); + } + } + size = MAKELONG(w + 8, HIWORD(size)); + } + } + break; + default: + size = MLSkinnedButton_GetIdealSize(hctrl, NULL); + break; + } + + INT width = LOWORD(size), height = HIWORD(size); + if (width < 82) width = 82; + if (height < 14) height = 14; + + hdwp = DeferWindowPos(hdwp, hctrl, NULL, 0, 0, width, height, flags); + } + } + + EndDeferWindowPos(hdwp); + + SetWindowPos(hdlg, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | + SWP_NOZORDER | SWP_FRAMECHANGED | ((bRedraw) ? 0 : SWP_NOREDRAW)); +} + +static BOOL DataCmdBar_OnInitDialog(HWND hdlg, HWND hwndFocus, LPARAM lParam) +{ + MLSKINWINDOW sw; + sw.skinType = SKINNEDWND_TYPE_AUTO; + sw.style = SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWS_USESKINFONT; + sw.hwndToSkin = hdlg; + MLSkinWindow(plugin.hwndLibraryParent, &sw); + + + sw.hwndToSkin = GetDlgItem(hdlg, IDC_BTN_EJECT); + MLSkinWindow(plugin.hwndLibraryParent, &sw); + + sw.style |= SWBS_SPLITBUTTON; + sw.hwndToSkin = GetDlgItem(hdlg, IDC_BTN_PLAYEX); + MLSkinWindow(plugin.hwndLibraryParent, &sw); + + sw.style = SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWS_USESKINFONT; + sw.hwndToSkin = GetDlgItem(hdlg, IDC_BTN_COPY); + MLSkinWindow(plugin.hwndLibraryParent, &sw); + + + sw.skinType = SKINNEDWND_TYPE_STATIC; + sw.style = SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWS_USESKINFONT; + sw.hwndToSkin = GetDlgItem(hdlg, IDC_LBL_STATUS); + MLSkinWindow(plugin.hwndLibraryParent, &sw); + + hmlilButton = DataCmdBar_CreateImageList(); + + PlayEx_Initialize(hdlg); + + DataCmdBar_SetButtonImages(GetDlgItem(hdlg, IDC_BTN_EJECT), hmlilButton, IDB_EJECT2_NORMAL, + IDB_EJECT2_PRESSED, IDB_EJECT2_HIGHLIGHTED, IDB_EJECT2_DISABLED); + + DataCmdBar_UpdateControls(hdlg, FALSE); + return FALSE; +} + +static void DataCmdBar_OnDestroy(HWND hdlg) +{ + if (hmlilButton) + { + MLImageList_Destroy(plugin.hwndLibraryParent, hmlilButton); + hmlilButton = NULL; + } +} + +static void DataCmdBar_OnWindowPosChanged(HWND hdlg, WINDOWPOS *pwp) +{ + if (0 == (SWP_NOSIZE & pwp->flags) || 0 != (SWP_FRAMECHANGED & pwp->flags)) + { + HWND hctrl; + HDWP hdwp; + RECT rc, rw; + DWORD flags; + + if (!GetClientRect(hdlg, &rc)) return; + InflateRect(&rc, -2, 0); + LONG left = rc.left-2; + LONG right = rc.right; + + hdwp = BeginDeferWindowPos(4); + if (!hdwp) return; + + flags = SWP_NOACTIVATE | SWP_NOZORDER | ((SWP_NOREDRAW | SWP_NOCOPYBITS) & pwp->flags); + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_BTN_PLAYEX)) && GetWindowRect(hctrl, &rw)) + { + hdwp = DeferWindowPos(hdwp, hctrl, NULL, left, rc.top, rw.right - rw.left, rc.bottom - rc.top, flags); + left += ((rw.right - rw.left) + 8); + } + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_BTN_COPY)) && GetWindowRect(hctrl, &rw)) + { + hdwp = DeferWindowPos(hdwp, hctrl, NULL, left, rc.top, rw.right - rw.left, rc.bottom - rc.top, flags); + left += ((rw.right - rw.left) + 8); + } + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_BTN_EJECT)) && GetWindowRect(hctrl, &rw)) + { + right -= (rw.right - rw.left); + if (right < (left + 16)) right = left + 16; + + hdwp = DeferWindowPos(hdwp, hctrl, NULL, right, rc.top, rw.right - rw.left, rc.bottom - rc.top, flags); + right -= 4; + } + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_LBL_STATUS)) && GetWindowRect(hctrl, &rw)) + { + hdwp = DeferWindowPos(hdwp, hctrl, NULL, left, rc.top, right - left, rc.bottom - rc.top, flags); + } + EndDeferWindowPos(hdwp); + } + if (0 == (SWP_NOREDRAW & pwp->flags)) InvalidateRect(GetDlgItem(hdlg, IDC_LBL_STATUS), NULL, TRUE); +} + +static void DataCmdBar_OnPlayDropDown(HWND hdlg, HWND hctrl) +{ + RECT r; + if (!GetWindowRect(hctrl, &r)) return; + + HWND hFileView = (HWND)CommandBar_GetData(hdlg); + if (NULL == hFileView) return; + + + HMENU hMenu = FileView_GetMenu(hFileView, FVMENU_PLAY); + if (!hMenu) return; + + + MLSkinnedButton_SetDropDownState(hctrl, TRUE); + + HMLIMGLST hmlilDropDown = DataCmdBar_CreateDropDownImageList(hMenu); + + MLTrackSkinnedPopupMenuEx(plugin.hwndLibraryParent, hMenu, + TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_BOTTOMALIGN | TPM_LEFTALIGN | TPM_NONOTIFY, + r.left, r.top - 2, hFileView, NULL, hmlilDropDown, r.right - r.left, + SMS_USESKINFONT, NULL, 0L); + + MLSkinnedButton_SetDropDownState(hctrl, FALSE); + MLImageList_Destroy(plugin.hwndLibraryParent, hmlilDropDown); +} + +static void DataCmdBar_OnPlayClick(HWND hdlg, HWND hButton) +{ + EnableWindow(hButton, FALSE); + + HWND hFileView = (HWND)CommandBar_GetData(hdlg); + if (NULL != hFileView) + { + HMENU hMenu = FileView_GetMenu(hFileView, FVMENU_PLAY); + if (NULL != hMenu) + { + UINT uCmd = (FVS_ENQUEUE & FileView_GetStyle(hFileView)) ? FVA_ENQUEUE : FVA_PLAY; + SendMessageW(hFileView, WM_COMMAND, MAKEWPARAM(FileView_GetActionCommand(hFileView, uCmd), 0), 0L); + } + } + + EnableWindow(hButton, TRUE); + +} + +static void DataCmdBar_OnCommand(HWND hdlg, INT eventId, INT ctrlId, HWND hwndCtrl) +{ + switch (ctrlId) + { + case IDC_BTN_PLAYEX: + switch(eventId) + { + case MLBN_DROPDOWN: DataCmdBar_OnPlayDropDown(hdlg, hwndCtrl); break; + case BN_CLICKED: DataCmdBar_OnPlayClick(hdlg, hwndCtrl); break; + } + break; + case IDC_BTN_EJECT: + switch(eventId) + { + case BN_CLICKED: SendMessageW(GetParent(hdlg), WM_COMMAND, MAKEWPARAM(ID_EJECT_DISC, 0), 0L); break; // straight to container... + } + break; + case IDC_BTN_COPY: + switch(eventId) + { + case BN_CLICKED: SendMessageW(hdlg, WM_COMMAND, MAKEWPARAM(ID_COPY_SELECTION, 0), 0L); break; + } + break; + } +} + + +static INT DataCmdBar_OnGetBestHeight(HWND hdlg) +{ + INT h, height = 0; + INT buttonList[] = { IDC_BTN_PLAYEX, }; + + for(int i =0; i < sizeof(buttonList)/sizeof(buttonList[0]); i++) + { + HWND hctrl = GetDlgItem(hdlg, buttonList[i]); + if (NULL != hctrl) + { + DWORD sz = MLSkinnedButton_GetIdealSize(hctrl, NULL); + h = HIWORD(sz); + if (height < h) height = h; + } + } + + return height; +} + +INT_PTR WINAPI DataCmdBar_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: return DataCmdBar_OnInitDialog(hdlg, (HWND)wParam, lParam); + case WM_DESTROY: DataCmdBar_OnDestroy(hdlg); break; + case WM_WINDOWPOSCHANGED: DataCmdBar_OnWindowPosChanged(hdlg, (WINDOWPOS*)lParam); return TRUE; + case WM_COMMAND: DataCmdBar_OnCommand(hdlg, HIWORD(wParam), LOWORD(wParam), (HWND)lParam); break; + case CBM_GETBESTHEIGHT: SetWindowLongPtrW(hdlg, DWLP_MSGRESULT, DataCmdBar_OnGetBestHeight(hdlg)); return TRUE; + case WM_DISPLAYCHANGE: + PlayEx_Initialize(hdlg); + break; + case WM_SETFONT: + DataCmdBar_UpdateControls(hdlg, LOWORD(lParam)); + return 0; + case WM_SETTEXT: + case WM_GETTEXT: + case WM_GETTEXTLENGTH: + SetWindowLongPtrW(hdlg, DWLP_MSGRESULT, (LONGX86)(LONG_PTR)SendDlgItemMessageW(hdlg, IDC_LBL_STATUS, uMsg, wParam, lParam)); + return TRUE; + + } + + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/commandbar.cpp b/Src/Plugins/Library/ml_disc/commandbar.cpp new file mode 100644 index 00000000..ef560c68 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/commandbar.cpp @@ -0,0 +1,119 @@ +#include "main.h" +#include "./commandbar.h" + +typedef struct _CMDBAR +{ + HWND hwndOwner; + DLGPROC fnDlgProc; + ULONG_PTR uData; +} CMDBAR; + +#define GetBarData(/*HWND*/ __hwndCmdBar) ((CMDBAR*)GetPropW((__hwndCmdBar), L"MLDISCCMDBAR")) + + +static BOOL CommandBar_OnInitDialog(HWND hdlg, HWND hwndFocus, LPARAM lParam) +{ + CMDBARCREATESTRUCT *pcbcs = (CMDBARCREATESTRUCT*)lParam; + if (pcbcs && pcbcs->fnDialogProc) + { + CMDBAR *pcb = (CMDBAR*)calloc(1, sizeof(CMDBAR)); + if (pcb) + { + pcb->fnDlgProc = pcbcs->fnDialogProc; + pcb->hwndOwner = pcbcs->hwndOwner; + pcb->uData = pcbcs->uData; + if (!SetPropW(hdlg, L"MLDISCCMDBAR", (HANDLE)pcb)) + { + free(pcb); + DestroyWindow(hdlg); + } + else return pcbcs->fnDialogProc(hdlg, WM_INITDIALOG, (WPARAM)hwndFocus, pcbcs->uData); + } + } + return FALSE; +} + +static void CommandBar_OnDestroy(HWND hdlg) +{ + CMDBAR *pcb = GetBarData(hdlg); + if (pcb) + { + RemovePropW(hdlg, L"MLDISCCMDBAR"); + free(pcb); + } +} + +static BOOL CALLBACK CommandBar_EnumChildHeight(HWND hwnd, LPARAM param) +{ + if (!param) return FALSE; + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE); + if (hdc) + { + HFONT hf = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L); + if (NULL == hf) hf = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + if (NULL != hf) + { + TEXTMETRICW tm = {0}; + HFONT hfo = (HFONT)SelectObject(hdc, hf); + if (GetTextMetricsW(hdc, &tm)) + { + INT *pmh = (INT*)param; + if (tm.tmHeight > *pmh) *pmh = tm.tmHeight; + } + SelectObject(hdc, hfo); + } + ReleaseDC(hwnd, hdc); + } + return TRUE; + +} +static INT CommandBar_OnGetBestHeight(HWND hwnd) +{ + INT maxHeight = 0; + EnumChildWindows(hwnd, CommandBar_EnumChildHeight, (LPARAM)&maxHeight); + if (maxHeight != 0) maxHeight += 2; + return maxHeight; +} + +INT_PTR CALLBACK CommandBar_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + CMDBAR *pcb = GetBarData(hdlg); + if (!pcb) + { + if (WM_INITDIALOG == uMsg) return CommandBar_OnInitDialog(hdlg, (HWND)wParam, lParam); + return 0; + } + if (pcb->fnDlgProc(hdlg, uMsg, wParam, lParam)) + { + if (WM_DESTROY == uMsg) CommandBar_OnDestroy(hdlg); + return TRUE; + } + + switch(uMsg) + { + case WM_DESTROY: CommandBar_OnDestroy(hdlg); return TRUE; + case WM_COMMAND: + if (pcb->hwndOwner) SendMessageW(pcb->hwndOwner, uMsg, wParam, lParam); return TRUE; + break; + + case CBM_GETBESTHEIGHT: MSGRESULT(hdlg, CommandBar_OnGetBestHeight(hdlg)); + case CBM_GETOWNER: MSGRESULT(hdlg, pcb->hwndOwner); + case CBM_SETOWNER: + SetWindowLongPtrW(hdlg, DWLP_MSGRESULT, (LONGX86)(LONG_PTR)pcb->hwndOwner); + pcb->hwndOwner = (HWND)lParam; + return TRUE; + case CBM_GETDATA: + { + CMDBAR *pBar = GetBarData(hdlg); + MSGRESULT(hdlg, (pBar) ? pBar->uData : NULL); + } + case CBM_SETDATA: + { + CMDBAR *pBar = GetBarData(hdlg); + if (pBar) pBar->uData = (ULONG_PTR)lParam; + MSGRESULT(hdlg, (NULL != pBar)); + } + + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/commandbar.h b/Src/Plugins/Library/ml_disc/commandbar.h new file mode 100644 index 00000000..6ff90583 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/commandbar.h @@ -0,0 +1,48 @@ +#ifndef NULLOSFT_MEDIALIBRARY_COMMANDBAR_CONTROL_HEADER +#define NULLOSFT_MEDIALIBRARY_COMMANDBAR_CONTROL_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CBM_FIRST +#define CBM_FIRST (WM_APP + 100) +#endif + +#define CBM_GETBESTHEIGHT (CBM_FIRST + 1) +#define CBM_GETOWNER (CBM_FIRST + 2) +#define CBM_SETOWNER (CBM_FIRST + 3) +#define CBM_GETDATA (CBM_FIRST + 4) +#define CBM_SETDATA (CBM_FIRST + 5) + +#define CommandBar_GetBestHeight(/*HWND*/ __hwndCB)\ + ((INT)(INT_PTR)SENDMSG((__hwndCB), CBM_GETBESTHEIGHT, 0, 0L)) + +#define CommandBar_GetOwner(/*HWND*/ __hwndCB)\ + ((HWND)SENDMSG((__hwndCB), CBM_GETOWNER, 0, 0L)) + +#define CommandBar_SetOwner(/*HWND*/ __hwndCB, /*HWND*/ __hwndNewOwner)\ + ((BOOL)SENDMSG((__hwndCB), CBM_SETOWNER, 0, (LPARAM)(__hwndNewOwner))) + +#define CommandBar_GetData(/*HWND*/ __hwndCB)\ + ((HWND)SENDMSG((__hwndCB), CBM_GETDATA, 0, 0L)) + +#define CommandBar_SetData(/*HWND*/ __hwndCB, /*ULONG_PTR*/ __userData)\ + ((BOOL)SENDMSG((__hwndCB), CBM_SETDATA, 0, (LPARAM)(__userData))) + + + + +#ifdef __cplusplus +} +#endif + + + +#endif // NULLOSFT_MEDIALIBRARY_COMMANDBAR_CONTROL_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/config.cpp b/Src/Plugins/Library/ml_disc/config.cpp new file mode 100644 index 00000000..71474145 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/config.cpp @@ -0,0 +1,129 @@ +#include "main.h" +#include "./config.h" +#include <shlwapi.h> +#include <strsafe.h> + +#define DEFAULT_SECTION TEXT("gen_ml_config") + +#define STRCOMP_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) + +C_Config::~C_Config() +{ + if (m_inifile) CoTaskMemFree(m_inifile); +} + +C_Config::C_Config(LPCTSTR pszIniFile) +{ + if (S_OK != SHStrDup(pszIniFile, &m_inifile)) + m_inifile = NULL; +} + +void C_Config::WriteIntEx(LPCTSTR pszSection, LPCTSTR pszKey, int nValue) +{ + TCHAR buf[32] = {0}; + StringCchPrintf(buf, ARRAYSIZE(buf), TEXT("%d"), nValue); + WriteStringEx(pszSection, pszKey, buf); +} + +int C_Config::ReadIntEx(LPCTSTR pszSection, LPCTSTR pszKey, int nDefault) +{ + return GetPrivateProfileInt(pszSection, pszKey, nDefault, m_inifile); +} + +void C_Config::WriteStringEx(LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszValue) +{ + WritePrivateProfileString(pszSection, pszKey, pszValue, m_inifile); + } + +LPTSTR C_Config::ReadCbStringEx(LPTSTR pszBuffer, INT cbBuffer, LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszDefault) +{ + return ReadCchStringEx(pszBuffer, cbBuffer/sizeof(TCHAR), pszSection, pszKey, pszDefault); +} + +LPTSTR C_Config::ReadCchStringEx(LPTSTR pszBuffer, INT cchBuffer, LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszDefault) +{ + const static TCHAR foobuf[] = TEXT("___________gen_ml_lameness___________"); + pszBuffer[0] = TEXT('\0'); + GetStringEx(pszSection, pszKey, foobuf, pszBuffer, cchBuffer); + pszBuffer[cchBuffer -1] = TEXT('\0'); + if (CSTR_EQUAL == CompareString(STRCOMP_INVARIANT, 0, foobuf, -1, pszBuffer, -1)) + { + if (S_OK != StringCchCopyEx(pszBuffer, cchBuffer, pszDefault, NULL, NULL, STRSAFE_IGNORE_NULLS)) + return NULL; + } + return pszBuffer; +} + +LPTSTR C_Config::ReadCchQuotedString(LPTSTR pszBuffer, INT cchBuffer, LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszDefault) +{ + LPTSTR p = ReadCchStringEx(pszBuffer, cchBuffer, pszSection, pszKey, pszDefault); + if (p) PathUnquoteSpaces(pszBuffer); + return p; +} + +LPTSTR C_Config::ReadCbQuotedString(LPTSTR pszBuffer, INT cbBuffer, LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszDefault) +{ + return ReadCchQuotedString(pszBuffer, cbBuffer/sizeof(TCHAR), pszSection, pszKey, pszDefault); +} + +void C_Config::WriteQuotedString(LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszValue) +{ + if (!pszValue) return; + INT cch = lstrlen(pszValue); + if (cch < MAX_PATH) + { + TCHAR szBuffer[MAX_PATH] = {0}; + if (S_OK == StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), pszValue)) + { + PathQuoteSpaces(szBuffer); + WriteStringEx(pszSection, pszKey, szBuffer); + return; + } + } + else + { + LPTSTR pszBuffer = (LPTSTR)calloc((cch + 4), sizeof(TCHAR)); + if (pszBuffer) + { + if (S_OK == StringCchCopy(pszBuffer, cch + 4, pszValue)) + { + PathQuoteSpaces(pszBuffer); + WriteStringEx(pszSection, pszKey, pszBuffer); + free(pszBuffer); + return; + } + free(pszBuffer); + } + } + WriteStringEx(pszSection, pszKey, pszValue); +} + +DWORD C_Config::GetStringEx(LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszDefault, LPTSTR pszReturnedValue, DWORD nSize) +{ + return GetPrivateProfileString(pszSection, pszKey, pszDefault, pszReturnedValue, nSize, m_inifile); +} + +void C_Config::WriteInt(LPCTSTR pszKey, int nValue) +{ + WriteIntEx(DEFAULT_SECTION, pszKey, nValue); +} + +int C_Config::ReadInt(LPCTSTR pszKey, int nDefault) +{ + return ReadIntEx(DEFAULT_SECTION, pszKey, nDefault); +} + +void C_Config::WriteString(LPCTSTR pszKey, LPCTSTR pszValue) +{ + WriteStringEx(DEFAULT_SECTION, pszKey, pszValue); +} + +LPCTSTR C_Config::ReadString(LPCTSTR pszKey, LPCTSTR pszDefault) +{ + static TCHAR szBuffer[4096]; + return ReadCchStringEx(szBuffer, ARRAYSIZE(szBuffer), DEFAULT_SECTION, pszKey, pszDefault); +} +DWORD C_Config::GetString(LPCTSTR pszKey, LPCTSTR pszDefault, LPTSTR pszReturnedValue, DWORD nSize) +{ + return GetStringEx(DEFAULT_SECTION, pszKey, pszDefault, pszReturnedValue, nSize); +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/config.h b/Src/Plugins/Library/ml_disc/config.h new file mode 100644 index 00000000..6ec17685 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/config.h @@ -0,0 +1,44 @@ +#ifndef _C_CONFIG_H_ +#define _C_CONFIG_H_ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#define C_CONFIG_WIN32NATIVE +#include <windows.h> + +class C_Config +{ + public: + C_Config(LPCTSTR pszIniFile); + ~C_Config(); + + void WriteIntEx(LPCTSTR pszSection, LPCTSTR pszKey, int nValue); + void WriteStringEx(LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszValue); + int ReadIntEx(LPCTSTR pszSection, LPCTSTR pszKey, int nDefault); + LPTSTR ReadCchStringEx(LPTSTR pszBuffer, INT cchBuffer, LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszDefault); + LPTSTR ReadCbStringEx(LPTSTR pszBuffer, INT cbBuffer, LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszDefault); + DWORD GetStringEx(LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszDefault, LPTSTR pszReturnedValue, DWORD nSize); + + void WriteBoolEx(LPCTSTR pszSection, LPCTSTR pszKey, int nValue) { WriteIntEx(pszSection, pszKey, ( 0 != nValue)); } + BOOL ReadBoolEx(LPCTSTR pszSection, LPCTSTR pszKey, int nDefault) { return (0 != ReadIntEx(pszSection, pszKey, nDefault)); } + + LPTSTR ReadCchQuotedString(LPTSTR pszBuffer, INT cchBuffer, LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszDefault); + LPTSTR ReadCbQuotedString(LPTSTR pszBuffer, INT cbBuffer, LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszDefault); + void WriteQuotedString(LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszValue); + + void WriteInt(LPCTSTR pszKey, int nValue); + void WriteString(LPCTSTR pszKey, LPCTSTR pszValue); + int ReadInt(LPCTSTR pszKey, int nDefault); + LPCTSTR ReadString(LPCTSTR pszKey, LPCTSTR pszDefault); + DWORD GetString(LPCTSTR pszKey, LPCTSTR pszDefault, LPTSTR pszReturnedValue, DWORD nSize); + + void WriteBool(LPCTSTR pszKey, int nValue) { WriteInt(pszKey, ( 0 != nValue)); } + BOOL ReadBool(LPCTSTR pszKey, int nDefault) { return (0 != ReadInt(pszKey, nDefault)); } + + private: + TCHAR *m_inifile; +}; + +#endif//_C_CONFIG_H_ diff --git a/Src/Plugins/Library/ml_disc/copyfiles.cpp b/Src/Plugins/Library/ml_disc/copyfiles.cpp new file mode 100644 index 00000000..426bd79d --- /dev/null +++ b/Src/Plugins/Library/ml_disc/copyfiles.cpp @@ -0,0 +1,613 @@ +#include "main.h" +#include "./copyfiles.h" +#include "./copyinternal.h" +#include "./resource.h" +#include "./settings.h" +#include "../nu/trace.h" +#include <api/service/waServiceFactory.h> +#include <shlwapi.h> +#include <strsafe.h> + +static LONG szBusyDrive[26] = {0, }; +static CRITICAL_SECTION cs_copy = { 0,}; + +static void NotifyDialog(COPYDATA *pcd, UINT uTask, UINT uOperation, LPARAM lParam) +{ + if(pcd->hDialog) PostMessage(pcd->hDialog, CFM_NOTIFY, MAKEWPARAM(uTask, uOperation), lParam); +} + +static INT_PTR QueryDialog(COPYDATA *pcd, UINT uTask, UINT uOperation, LPARAM lParam) +{ + return (pcd->hDialog) ? SendMessage(pcd->hDialog, CFM_NOTIFY, MAKEWPARAM(uTask, uOperation), lParam) : FALSE; +} + +static void CopyFiles_MarkDrivesBusy(LPCTSTR *ppsz, INT count, BOOL bBusy) +{ + INT i, n; + DWORD driveMask = 0x00; + + EnterCriticalSection(&cs_copy); + if (bBusy) + { + for(i = 0; i < count; i++) + { + n = PathGetDriveNumber(ppsz[i]); + if (-1 != n) + { + if (0 == szBusyDrive[n]) driveMask |= (((DWORD)0x01) << n); + szBusyDrive[n]++; + } + } + } + else + { + for(i = 0; i < count; i++) + { + n = PathGetDriveNumber(ppsz[i]); + if (-1 != n) + { + if (szBusyDrive[n] <= 0) continue; + szBusyDrive[n]--; + if (0 == szBusyDrive[n]) driveMask |= (((DWORD)0x01) << n); + } + } + } + LeaveCriticalSection(&cs_copy); + + if (0x00 != driveMask) + { + static UINT uMsgCopyNotify = 0; + if (!uMsgCopyNotify) uMsgCopyNotify = RegisterWindowMessageA("WACOPY_BROADCAST_MSG"); + if (uMsgCopyNotify) + { + for (CHAR c = 'A'; 0x00 != driveMask; c++, driveMask>>=1) + { + if (0 == (0x01 & driveMask)) continue; + if (bBusy) SendNotifyMessage(HWND_BROADCAST, uMsgCopyNotify, MAKEWPARAM(c, 0), (LPARAM)TRUE); + else + { + SendNotifyMessage(HWND_BROADCAST, uMsgCopyNotify, MAKEWPARAM(c, 0), (LPARAM)FALSE); + SendNotifyMessage(HWND_BROADCAST, uMsgCopyNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent); + } + } + } + } +} +static BOOL ReadCopyParameters(COPYDATA *pcd) +{ + BOOL bVal; + HRESULT hr = S_OK; + pcd->uFlags = 0; + if (S_OK == hr) hr = Settings_ReadString(C_COPY, CF_PATH, pcd->szDestination, ARRAYSIZE(pcd->szDestination)); + if (S_OK == hr) hr = Settings_ReadString(C_COPY, CF_TITLEFMT, pcd->szTitleFormat, ARRAYSIZE(pcd->szTitleFormat)); + if (S_OK == hr && S_OK == (hr = Settings_GetBool(C_COPY, CF_ADDTOMLDB, &bVal)) && bVal) pcd->uFlags |= FCF_ADDTOMLDB; + if (S_OK == hr && S_OK == (hr = Settings_GetBool(C_COPY, CF_USETITLEFMT, &bVal)) && bVal) pcd->uFlags |= FCF_USETITLEFMT; + CleanupDirectoryString(pcd->szDestination); + + return (S_OK == hr); + +} + +void MLDisc_InitializeCopyData() +{ + InitializeCriticalSection(&cs_copy); +} + +void MLDisc_ReleaseCopyData() +{ + DeleteCriticalSection(&cs_copy); +} + +BOOL MLDisc_IsDiscCopying(CHAR cLetter) +{ + if (cLetter >= 'a' && cLetter <= 'z') cLetter -= 0x20; + return (cLetter >= 'A' && cLetter <= 'Z' && szBusyDrive[cLetter - 'A'] > 0); +} + + +BOOL MLDisc_CopyFiles(HWND hParent, LPWSTR *ppszFiles, ULONGLONG *pFSizes, INT count) +{ + if (!ppszFiles || !count) return FALSE; + if (NULL == hParent) hParent = plugin.hwndLibraryParent; + + COPYDATA *pcd = (COPYDATA*)CoTaskMemAlloc(sizeof(COPYDATA)); + if (!pcd) return FALSE; + ZeroMemory(pcd, sizeof(COPYDATA)); + + CopyFiles_AddRef(pcd); + + pcd->hOwner = hParent; + pcd->ppszFiles = ppszFiles; + pcd->pFSizes = pFSizes; + pcd->count = count; + pcd->bCancel = FALSE; + + waServiceFactory *factory = plugin.service->service_getServiceByGuid(api_metadataGUID); + if (factory) pcd->pMetaReader = (api_metadata*) factory->getInterface(); + factory = plugin.service->service_getServiceByGuid(mldbApiGuid); + if (factory) pcd->pMlDb = (api_mldb*) factory->getInterface(); + + HWND hRoot = GetAncestor(hParent, GA_ROOT); + if (NULL == hRoot) hRoot = hParent; + + INT_PTR result = WASABI_API_DIALOGBOXPARAMW(IDD_FILECOPY_PREPARE, hRoot, CopyPrepare_DialogProc, (LPARAM)pcd); + if (IDCANCEL != result) + { + if (ReadCopyParameters(pcd)) + { + HWND hCopy = WASABI_API_CREATEDIALOGPARAMW(IDD_FILECOPY_PROGRESS, hRoot, CopyProgress_DialogProc, (LPARAM)pcd); + if (hCopy) + { + pcd->hDialog = hCopy; + ShowWindow(hCopy, SW_SHOWNORMAL); + RedrawWindow(hCopy, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + } + CopyFiles_StartCopy(pcd); + } + } + + CopyFiles_Release(pcd); + return TRUE; +} + +BOOL CopyFiles_CancelCopy(COPYDATA *pcd) +{ + if (pcd) pcd->bCancel = TRUE; + return (NULL != pcd); +} + +LONG CopyFiles_AddRef(COPYDATA *pcd) +{ + return (pcd) ? InterlockedIncrement(&pcd->ref) : 0; + +} +LONG CopyFiles_Release(COPYDATA *pcd) +{ + if (pcd && pcd->ref > 0) + { + LONG r = InterlockedDecrement(&pcd->ref); + if ( 0 == r) + { + if (pcd->ppszFiles) + { + for (int i = 0; i < pcd->count; i++) CoTaskMemFree(pcd->ppszFiles[i]); + CoTaskMemFree(pcd->ppszFiles); + } + if (pcd->pFSizes) CoTaskMemFree(pcd->pFSizes); + if (pcd->hThread) CloseHandle(pcd->hThread); + + if(pcd->pMetaReader) + { + waServiceFactory *factory = plugin.service->service_getServiceByGuid(api_metadataGUID); + if (factory) factory->releaseInterface(pcd->pMetaReader); + } + if(pcd->pMlDb) + { + waServiceFactory *factory = plugin.service->service_getServiceByGuid(mldbApiGuid); + if (factory) factory->releaseInterface(pcd->pMlDb); + } + CoTaskMemFree(pcd); + } + return r; + } + return 0; +} + +static ULONGLONG CopyFiles_CalculateTotalSize(COPYDATA *pcd) +{ + ULONGLONG total = 0; + if (!pcd->pFSizes) + { + pcd->pFSizes = (ULONGLONG*)CoTaskMemAlloc(sizeof(ULONGLONG)*pcd->count); + if (!pcd->pFSizes) + { + pcd->errorCode = ERROR_NOT_ENOUGH_MEMORY; + return 0; + } + LARGE_INTEGER fs; + for(int i = 0; i < pcd->count; i++) + { + HANDLE hFile = CreateFile(pcd->ppszFiles[i], FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + if (INVALID_HANDLE_VALUE == hFile) + { + pcd->errorCode = GetLastError(); + return 0; + } + if (!GetFileSizeEx(hFile, &fs)) { pcd->errorCode = GetLastError(); CloseHandle(hFile); return 0; } + CloseHandle(hFile); + pcd->pFSizes[i] = fs.QuadPart; + } + } + for(int i = 0; i < pcd->count; i++) total += pcd->pFSizes[i]; + return total; +} + +BOOL CopyFiles_CreateDirectory(LPCTSTR pszDirectory) +{ + DWORD ec = ERROR_SUCCESS; + if (!CreateDirectory(pszDirectory, NULL)) + { + ec = GetLastError(); + if (ERROR_PATH_NOT_FOUND == ec) + { + LPCTSTR pszBlock = pszDirectory; + TCHAR szBuffer[MAX_PATH] = {0}; + + LPCTSTR pszCursor = PathFindNextComponent(pszBlock); + ec = (pszCursor == pszBlock || S_OK != StringCchCopyN(szBuffer, ARRAYSIZE(szBuffer), pszBlock, (pszCursor - pszBlock))) ? + ERROR_INVALID_NAME : ERROR_SUCCESS; + + pszBlock = pszCursor; + + while (ERROR_SUCCESS == ec && NULL != (pszCursor = PathFindNextComponent(pszBlock))) + { + if (pszCursor == pszBlock || S_OK != StringCchCatN(szBuffer, ARRAYSIZE(szBuffer), pszBlock, (pszCursor - pszBlock))) + ec = ERROR_INVALID_NAME; + + if (ERROR_SUCCESS == ec && !CreateDirectory(szBuffer, NULL)) + { + ec = GetLastError(); + if (ERROR_ALREADY_EXISTS == ec) ec = ERROR_SUCCESS; + } + pszBlock = pszCursor; + } + } + + if (ERROR_ALREADY_EXISTS == ec) ec = ERROR_SUCCESS; + } + SetLastError(ec); + return (ERROR_SUCCESS == ec); +} + + +static BOOL CopyFiles_CheckDestination(COPYDATA *pcd, ULONGLONG needSize) +{ + TCHAR szRoot[MAX_PATH] = {0}; + if (S_OK != StringCchCopy(szRoot, ARRAYSIZE(szRoot), pcd->szDestination)) + { + pcd->errorCode = ERROR_OUTOFMEMORY; + return FALSE; + } + PathStripToRoot(szRoot); + ULARGE_INTEGER free, total; + if (!GetDiskFreeSpaceEx(szRoot, &free, &total, NULL)) + { + pcd->errorCode = GetLastError(); + return FALSE; + } + if (needSize > free.QuadPart) + { + pcd->errorCode = ERROR_DISK_FULL; + return FALSE; + } + + if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(pcd->szDestination)) + { + DWORD ec = GetLastError(); + if (ERROR_PATH_NOT_FOUND == ec || ERROR_FILE_NOT_FOUND == ec) + { + if (TRUE == QueryDialog(pcd, CFT_CONFLICT, CFO_DESTNOTEXIST, (LPARAM)pcd->szDestination)) + pcd->errorCode = ERROR_REQUEST_ABORTED; + } + else pcd->errorCode = ec; + + if (ERROR_SUCCESS != pcd->errorCode) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_DIRECTORYCREATE_FAILED; + return FALSE; + } + + } + + if (!CopyFiles_CreateDirectory(pcd->szDestination)) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_DIRECTORYCREATE_FAILED; + pcd->errorCode = ERROR_CANNOT_MAKE; + return FALSE; + } + return TRUE; +} + +static BOOL CopyFiles_FixCdAttributes(LPCTSTR pszFileName) +{ + DWORD attr = GetFileAttributes(pszFileName); + if (INVALID_FILE_ATTRIBUTES == attr) return FALSE; + return SetFileAttributes(pszFileName, (attr & ~FILE_ATTRIBUTE_READONLY) | FILE_ATTRIBUTE_ARCHIVE); +} + + + +static BOOL CopyFiles_DeleteFile(LPCTSTR pszFileName, COPYDATA *pcd) +{ + DWORD attr = GetFileAttributes(pszFileName); + if (INVALID_FILE_ATTRIBUTES == attr) return FALSE; + if (FILE_ATTRIBUTE_READONLY & attr) + { + BOOL bReset = FALSE; + if (FCF_DELETEREADONLY & pcd->uFlags) bReset = TRUE; + else + { + INT_PTR r = QueryDialog(pcd, CFT_CONFLICT, CFO_READONLY, (LPARAM)pszFileName); + switch(r) + { + case READONLY_CANCELCOPY: + pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_USERABORT; + SetLastError(ERROR_REQUEST_ABORTED); + return FALSE; + case READONLY_DELETEALL: pcd->uFlags |= FCF_DELETEREADONLY; // no break + case READONLY_DELETE: bReset = TRUE; break; + } + } + + if (bReset) + { + if (!SetFileAttributes(pszFileName, (attr & ~FILE_ATTRIBUTE_READONLY))) + return FALSE; + } + } + return DeleteFile(pszFileName); +} + +#define NOT_EXIST 0 +#define EXIST_AND_SKIP 1 +#define EXIST_AND_OVERWRITE 2 +#define EXIST_AND_CANCEL 3 + +static DWORD CopyFiles_CheckIfExist(LPCTSTR pszFileNameDest, LPCTSTR pszFileNameSource, COPYDATA *pcd) +{ + if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(pszFileNameDest)) + { + return NOT_EXIST; + } + + + if (FCF_SKIPFILE & pcd->uFlags) return EXIST_AND_SKIP; + if (FCF_OVERWRITEFILE & pcd->uFlags) return EXIST_AND_OVERWRITE; + + FILECONFLICT conflict; + ZeroMemory(&conflict, sizeof(FILECONFLICT)); + + pcd->uFlags &= ~(FCF_SKIPFILE | FCF_OVERWRITEFILE); + + conflict.pszNameExisting = pszFileNameDest; + conflict.pszNameNew = pszFileNameSource; + + INT_PTR r = QueryDialog(pcd, CFT_CONFLICT, CFO_FILEALREDYEXIST, (LPARAM)&conflict); + + switch(0xFF & r) + { + case EXISTFILE_CANCELCOPY: return EXIST_AND_CANCEL; + case EXISTFILE_SKIP: + if (EXISTFILE_APPLY_TO_ALL & r) pcd->uFlags |= FCF_SKIPFILE; + return EXIST_AND_SKIP; + case EXISTFILE_OVERWRITE: + if (EXISTFILE_APPLY_TO_ALL & r) pcd->uFlags |= FCF_OVERWRITEFILE; + return EXIST_AND_OVERWRITE; + } + + return NOT_EXIST; +} + +typedef struct _COPYPROGRESS +{ + ULONGLONG total; + ULONGLONG completed; + HWND hDialog; + INT percent; +} COPYPROGRESS; + +static DWORD CALLBACK CopyFiles_ProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize, + LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason, + HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData) +{ + COPYPROGRESS *pProgress = (COPYPROGRESS*)lpData; + if (pProgress) + { + switch(dwCallbackReason) + { + case CALLBACK_STREAM_SWITCH: + pProgress->completed += TotalFileSize.QuadPart; + break; + + } + INT p = (INT)((pProgress->completed - TotalFileSize.QuadPart + TotalBytesTransferred.QuadPart) * 100 / pProgress->total); + if (p != pProgress->percent) + { + pProgress->percent = p; + if (pProgress->hDialog) + PostMessage(pProgress->hDialog, CFM_NOTIFY, MAKEWPARAM(CFT_COPYING, CFO_PROGRESS), p); + } + } + return PROGRESS_CONTINUE; +}; + +static DWORD WINAPI CopyFiles_ThreadProc(LPVOID param) +{ + + COPYDATA *pcd = (COPYDATA*)param; + if (!pcd) return 1; + + CopyFiles_MarkDrivesBusy((LPCTSTR*)pcd->ppszFiles, pcd->count, TRUE); + + ULONGLONG needSize; + NotifyDialog(pcd, CFT_INITIALIZING, CFO_INIT, 0L); + NotifyDialog(pcd, CFT_INITIALIZING, CFO_CACLSIZE, 0L); + needSize = CopyFiles_CalculateTotalSize(pcd); + BOOL bSuccess = (ERROR_SUCCESS == pcd->errorCode); + if (bSuccess) + { + NotifyDialog(pcd, CFT_INITIALIZING, CFO_CHECKDESTINATION, 0L); + bSuccess = CopyFiles_CheckDestination(pcd, needSize); + } + + if (!bSuccess) + { + if (0 == pcd->errorMsgId) + pcd->errorMsgId = IDS_COPY_ERRMSG_INITIALIZATION_FAILED; + NotifyDialog(pcd, CFT_FINISHED, CFO_FAILED, pcd->errorCode); + CopyFiles_MarkDrivesBusy((LPCTSTR*)pcd->ppszFiles, pcd->count, FALSE); + CopyFiles_Release(pcd); + return 0; + } + + COPYPROGRESS progress; + ZeroMemory(&progress, sizeof(COPYPROGRESS)); + progress.total = needSize; + progress.hDialog = pcd->hDialog; + + NotifyDialog(pcd, CFT_COPYING, CFO_INIT, 0L); + + TCHAR szFile[MAX_PATH] = {0}; + + for (int i = 0; i < pcd->count && ERROR_SUCCESS == pcd->errorCode; i++) + { + if (pcd->bCancel) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_USERABORT; + pcd->errorCode = ERROR_REQUEST_ABORTED; + } + + LPCTSTR pszOrigFileName = PathFindFileName(pcd->ppszFiles[i]); + + NotifyDialog(pcd, CFT_COPYING, CFO_NEXTFILE, MAKELPARAM(i, pcd->count)); + + if (NULL == PathCombine(szFile, pcd->szDestination, pszOrigFileName)) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_FAILED; + pcd->errorCode = ERROR_BAD_PATHNAME; + } + + DWORD r = CopyFiles_CheckIfExist(szFile, pcd->ppszFiles[i], pcd); + switch(r) + { + case EXIST_AND_SKIP: + continue; + break; + case EXIST_AND_OVERWRITE: + if (!CopyFiles_DeleteFile(szFile, pcd)) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_DELETEFILE_FAILED; + pcd->errorCode = GetLastError(); + } + break; + case EXIST_AND_CANCEL: + pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_USERABORT; + pcd->errorCode = ERROR_REQUEST_ABORTED; + break; + } + + // copy + if (ERROR_SUCCESS == pcd->errorCode && !CopyFileEx(pcd->ppszFiles[i], szFile, CopyFiles_ProgressRoutine, &progress, &pcd->bCancel, 0)) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_FAILED; + pcd->errorCode = GetLastError(); + } + + if (pcd->bCancel) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_USERABORT; + pcd->errorCode = ERROR_REQUEST_ABORTED; + } + + if (ERROR_SUCCESS == pcd->errorCode) // post copy + { + // fix attributes + if (ERROR_SUCCESS == pcd->errorCode && !CopyFiles_FixCdAttributes(szFile)) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_SETATTRIBUTES_FAILED; + pcd->errorCode = GetLastError(); + } + + // format title & rename + if (ERROR_SUCCESS == pcd->errorCode && (FCF_USETITLEFMT & pcd->uFlags) && pcd->pMetaReader) + { + TCHAR szBuffer[MAX_PATH] = {0}; + if (!CopyFiles_FormatFileName(szBuffer, ARRAYSIZE(szBuffer), szFile, pszOrigFileName, + pcd->szDestination, pcd->szTitleFormat, pcd->pMetaReader)) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_TITLEFORMAT_FAILED; + pcd->errorCode = GetLastError(); + } + + if (pcd->bCancel) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_USERABORT; + pcd->errorCode = ERROR_REQUEST_ABORTED; + } + + if (ERROR_SUCCESS == pcd->errorCode && + CSTR_EQUAL != CompareString(STRCOMP_INVARIANT, 0, szBuffer, -1, szFile, -1)) + { + + DWORD r = CopyFiles_CheckIfExist(szBuffer, szFile, pcd); + switch(r) + { + case EXIST_AND_SKIP: + CopyFiles_DeleteFile(szFile, pcd); + continue; + break; + case EXIST_AND_OVERWRITE: + if (!CopyFiles_DeleteFile(szBuffer, pcd)) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_DELETEFILE_FAILED; + pcd->errorCode = GetLastError(); + } + break; + case EXIST_AND_CANCEL: + pcd->errorMsgId = IDS_COPY_ERRMSG_COPYFILE_USERABORT; + pcd->errorCode = ERROR_REQUEST_ABORTED; + break; + } + + if (ERROR_SUCCESS == pcd->errorCode) + { + if (!MoveFileEx(szFile, szBuffer, MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED)) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_TITLEFORMAT_FAILED; + pcd->errorCode = GetLastError(); + } + else StringCchCopy(szFile, ARRAYSIZE(szFile), szBuffer); + } + + } + } + + + if (ERROR_SUCCESS != pcd->errorCode) + { + CopyFiles_DeleteFile(szFile, pcd); + } + else if ((FCF_ADDTOMLDB & pcd->uFlags) && pcd->pMlDb) + { + if (0 == pcd->pMlDb->AddFile(szFile)) + { + pcd->errorMsgId = IDS_COPY_ERRMSG_ADDTOMLDB_FAILED; + pcd->errorCode = ERROR_FILE_NOT_FOUND; + } + } + } + + } + + NotifyDialog(pcd, CFT_FINISHED, (ERROR_SUCCESS == pcd->errorCode) ? CFO_SUCCESS : CFO_FAILED, pcd->errorCode); + if ((FCF_ADDTOMLDB & pcd->uFlags) && pcd->pMlDb) pcd->pMlDb->Sync(); + CopyFiles_MarkDrivesBusy((LPCTSTR*)pcd->ppszFiles, pcd->count, FALSE); + CopyFiles_Release(pcd); + return 0; +} + +BOOL CopyFiles_StartCopy(COPYDATA *pcd) +{ + DWORD threadId; + + CopyFiles_AddRef(pcd); + + pcd->hThread = CreateThread(NULL, 0, CopyFiles_ThreadProc, pcd, 0, &threadId); + if (pcd->hThread) return TRUE; + + + pcd->errorCode = GetLastError(); + NotifyDialog(pcd, CFT_FINISHED, CFO_FAILED, pcd->errorCode); + CopyFiles_Release(pcd); + return FALSE; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/copyfiles.h b/Src/Plugins/Library/ml_disc/copyfiles.h new file mode 100644 index 00000000..bd762f53 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/copyfiles.h @@ -0,0 +1,27 @@ +#ifndef NULLOSFT_MEDIALIBRARY_MLDISC_COPYFILES_HEADER +#define NULLOSFT_MEDIALIBRARY_MLDISC_COPYFILES_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +void MLDisc_InitializeCopyData(); +void MLDisc_ReleaseCopyData(); + +// use CoTaskMemAlloc/CoTackMemFree to allocate buffers and each string. pszFSize can be NULL. if return TRUE do not free data. +BOOL MLDisc_CopyFiles(HWND hParent, LPWSTR *ppszFiles, ULONGLONG *pFSizes, INT count); +BOOL MLDisc_IsDiscCopying(CHAR cLetter); +#ifdef __cplusplus +} +#endif + + + +#endif // NULLOSFT_MEDIALIBRARY_MLDISC_COPYFILES_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/copyfiles_post.cpp b/Src/Plugins/Library/ml_disc/copyfiles_post.cpp new file mode 100644 index 00000000..44893398 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/copyfiles_post.cpp @@ -0,0 +1,138 @@ +#include "main.h" +#include "./copyfiles.h" +#include "./copyinternal.h" +#include "./resource.h" +#include "../nu/trace.h" +#include <api/service/waServiceFactory.h> +#include <shlwapi.h> +#include <strsafe.h> + +typedef struct _FILEMETA +{ + LPWSTR pszArtist; + LPWSTR pszAlbum; + LPWSTR pszTitle; + LPWSTR pszGenre; + LPWSTR pszAlbumArtist; + INT nYear; + INT nTrackNum; + INT nTrackCount; + LPWSTR pszDisc; +} FILEMETA; + +// sets part and parts to -1 or 0 on fail/missing (e.g. parts will be -1 on "1", but 0 on "1/") +static void ParseIntSlashInt(wchar_t *string, int *part, int *parts) +{ + *part = -1; + *parts = -1; + + if (string && string[0]) + { + *part = _wtoi(string); + while (string && *string && *string != '/') + { + string++; + } + if (*string == '/') + { + string++; + *parts = _wtoi(string); + } + } +} + +#define READFILEINFO(__fileName, __tag, __result, __pszBuffer, __cchBuffer)\ + (pReader->GetExtendedFileInfo((__fileName), (__tag), (__pszBuffer), (__cchBuffer)) && L'\0' != *(__pszBuffer)) + + +static void CopyFiles_ReadFileMeta(FILEMETA *pMeta, api_metadata *pReader, LPCWSTR pszFileName) +{ + WCHAR szBuffer[2048] = {0}; + + #define GETFILEINFO_STR(__tag, __result, __resId)\ + { szBuffer[0] = L'\0';\ + READFILEINFO(pszFileName, __tag, __result, szBuffer, ARRAYSIZE(szBuffer));\ + if (TEXT('\0') == *szBuffer)\ + { if (IS_INTRESOURCE(__resId)) WASABI_API_LNGSTRINGW_BUF(((UINT)(UINT_PTR)(__resId)), szBuffer, ARRAYSIZE(szBuffer));\ + else StringCchCopyEx(szBuffer, ARRAYSIZE(szBuffer), (__resId), NULL, NULL, STRSAFE_IGNORE_NULLS);\ + }\ + (__result) = _wcsdup(szBuffer); } + #define GETFILEINFO_INT(__tag, __result) { szBuffer[0] = L'\0';\ + if (READFILEINFO(pszFileName, __tag, __result, szBuffer, ARRAYSIZE(szBuffer)))\ + {(__result) = _wtoi(szBuffer); }} + #define GETFILEINFO_INTINT(__tag, __result1, __result2) { szBuffer[0] = L'\0';\ + if (READFILEINFO(pszFileName, __tag, __result, szBuffer, ARRAYSIZE(szBuffer)))\ + {ParseIntSlashInt(szBuffer, (__result1), (__result2)); }} + + if (!pMeta) return; + ZeroMemory(pMeta, sizeof(FILEMETA)); + +#pragma warning(push) +#pragma warning(disable : 4127) + + GETFILEINFO_STR(L"artist", pMeta->pszArtist, MAKEINTRESOURCE(IDS_UNKNOWN_ARTIST)); + GETFILEINFO_STR(L"album", pMeta->pszAlbum, MAKEINTRESOURCE(IDS_UNKNOWN_ALBUM)); + GETFILEINFO_STR(L"title", pMeta->pszTitle, MAKEINTRESOURCE(IDS_UNKNOWN)); + GETFILEINFO_STR(L"albumartist", pMeta->pszAlbumArtist, pMeta->pszArtist); + GETFILEINFO_STR(L"genre", pMeta->pszGenre, MAKEINTRESOURCE(IDS_UNKNOWN_GENRE)); + GETFILEINFO_INT(L"year", pMeta->nYear); + GETFILEINFO_INTINT(L"track", &pMeta->nTrackNum, &pMeta->nTrackCount); + GETFILEINFO_STR(L"disc", pMeta->pszDisc, MAKEINTRESOURCE(IDS_UNKNOWN)); +#pragma warning(pop) +} + +static void CopyFiles_ReleaseFileMeta(FILEMETA *pMeta) +{ + if (pMeta->pszArtist) free(pMeta->pszArtist); + if (pMeta->pszAlbum) free(pMeta->pszAlbum); + if (pMeta->pszTitle) free(pMeta->pszTitle); + if (pMeta->pszGenre) free(pMeta->pszGenre); + if (pMeta->pszDisc) free(pMeta->pszDisc); + if (pMeta->pszAlbumArtist) free(pMeta->pszAlbumArtist); + ZeroMemory(pMeta, sizeof(FILEMETA)); +} + +static BOOL CopyFiles_GetFormattedName(LPTSTR pszBuffer, INT cchBufferMax, LPCTSTR pszFileToFormat, LPCTSTR pszOrigFileName, LPCTSTR pszFormat, api_metadata *pMetaReader) +{ + HRESULT hr; + FILEMETA meta; + CopyFiles_ReadFileMeta(&meta, pMetaReader, pszFileToFormat); + + WCHAR szYear[16] = {0}; + StringCchPrintf(szYear, ARRAYSIZE(szYear), TEXT("%d"), meta.nYear); + + pszBuffer[0] = TEXT('\0'); + hr = FormatFileName(pszBuffer, cchBufferMax, pszFormat, + meta.nTrackNum, meta.pszAlbumArtist, + meta.pszAlbum, meta.pszTitle, + meta.pszGenre, szYear, meta.pszArtist, + pszOrigFileName, meta.pszDisc); + + CopyFiles_ReleaseFileMeta(&meta); + + if (S_OK != hr) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + return TRUE; +} + +BOOL CopyFiles_FormatFileName(LPTSTR pszNewFileName, INT cchBufferMax, LPCTSTR pszFileToRename, LPCTSTR pszOrigFileName, LPCTSTR pszDestination, LPCTSTR pszFormat, api_metadata *pMetaReader) +{ + StringCchCopy(pszNewFileName, cchBufferMax, pszDestination); + INT l = lstrlen(pszNewFileName); + if (l) { pszNewFileName[l] = TEXT('\\'); pszNewFileName[l + 1] = TEXT('\0'); l++; } + if (!CopyFiles_GetFormattedName(pszNewFileName + l, cchBufferMax - l, pszFileToRename, pszOrigFileName, pszFormat, pMetaReader)) + return FALSE; + + LPTSTR p = PathFindFileName(pszNewFileName); + if (p && p > pszNewFileName) + { + *(p - 1) = TEXT('\0'); + if (!CopyFiles_CreateDirectory(pszNewFileName)) return FALSE; + *(p - 1) = TEXT('\\'); + } + return TRUE; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/copyinternal.h b/Src/Plugins/Library/ml_disc/copyinternal.h new file mode 100644 index 00000000..b59be7a6 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/copyinternal.h @@ -0,0 +1,125 @@ +#ifndef NULLOSFT_MEDIALIBRARY_MLDISC_COPYFILES_INTERNAL_HEADER +#define NULLOSFT_MEDIALIBRARY_MLDISC_COPYFILES_INTERNAL_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> +#include "../Agave/Metadata/api_metadata.h" +#include "../ml_local/api_mldb.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define STRCOMP_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) + +#define CPM_UPDATEDISKSIZE (WM_APP + 2) + + +typedef struct _COPYDATA +{ + LONG ref; + HWND hDialog; + HWND hOwner; + HANDLE hThread; + BOOL bCancel; + DWORD errorCode; + UINT errorMsgId; + LPWSTR *ppszFiles; + ULONGLONG *pFSizes; + INT count; + UINT uFlags; + api_metadata *pMetaReader; + api_mldb *pMlDb; + WCHAR szDestination[MAX_PATH]; + WCHAR szTitleFormat[128]; +} COPYDATA; + +#define FCF_ADDTOMLDB 0x00000002L +#define FCF_USETITLEFMT 0x00000004L +#define FCF_SKIPFILE 0x00010000L +#define FCF_OVERWRITEFILE 0x00020000L +#define FCF_DELETEREADONLY 0x00040000L + + + +INT_PTR CALLBACK CopyPrepare_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +INT_PTR CALLBACK CopyProgress_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + + +LONG CopyFiles_AddRef(COPYDATA *pcd); +LONG CopyFiles_Release(COPYDATA *pcd); +BOOL CopyFiles_StartCopy(COPYDATA *pcd); +BOOL CopyFiles_CancelCopy(COPYDATA *pcd); + +BOOL CopyFiles_CreateDirectory(LPCTSTR pszDirectory); +BOOL CopyFiles_FormatFileName(LPTSTR pszNewFileName, INT cchBufferMax, LPCTSTR pszFileToRename, LPCTSTR pszOrigFileName, LPCTSTR pszDestination, LPCTSTR pszFormat, api_metadata *pMetaReader); + +HBITMAP CopyFiles_LoadResourcePng(LPCTSTR pszResource); + +#define CFM_NOTIFY (WM_APP + 3) + +// notify task +#define CFT_INITIALIZING 0x0001 +#define CFT_COPYING 0x0002 +#define CFT_FINISHED 0x0003 +#define CFT_CONFLICT 0x0004 // conflicts always use SendMessage + + +// init task operations code +#define CFO_INIT 0x0000 +#define CFO_CACLSIZE 0x0001 +#define CFO_CHECKDESTINATION 0x0002 + + +// copy task operations code +#define CFO_INIT 0x0000 // time to set tast text +#define CFO_NEXTFILE 0x0001 // lParam - MAKELPARAM(file index, total count) +#define CFO_PROGRESS 0x0002 // lParam - percent +#define CFO_POSTCOPY 0x0003 + + +// conflicts + +#define EXISTFILE_CANCELCOPY 0x0001 // almost like return FALSE but will not produce error +#define EXISTFILE_SKIP 0x0002 // skip +#define EXISTFILE_OVERWRITE 0x0003 // overwrite +#define EXISTFILE_APPLY_ONCE 0x0000 // apply only once +#define EXISTFILE_APPLY_TO_ALL 0x0100 // apply to all files with the same conflict + +#define READONLY_CANCELCOPY 0x0001 +#define READONLY_DELETE 0x0002 +#define READONLY_DELETEALL 0x0003 + +typedef struct _FILECONFLICT +{ + LPCTSTR pszNameExisting; + LPCTSTR pszNameNew; +} FILECONFLICT; + + +#define CFO_DESTNOTEXIST 0x0000 // return FALSE to create destination or TRUE to cancel copy operation. param -pszDestionation +#define CFO_FILEALREDYEXIST 0x0001 // return FALSE to fail with access denied, or EXISTFILE_XXX, param = (FILECONFLICT*) +#define CFO_READONLY 0x0002 // return FALSE to fail, or RADONLY_XXX, param = (LPCTSTR)pszFileName + + + + + + +// finished task operations code +#define CFO_FAILED 0x0001 +#define CFO_SUCCESS 0x0002 +#define CFO_CANCELLED 0x0003 + + +#ifdef __cplusplus +} +#endif + + + +#endif // NULLOSFT_MEDIALIBRARY_MLDISC_COPYFILES_INTERNAL_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/copyprep.cpp b/Src/Plugins/Library/ml_disc/copyprep.cpp new file mode 100644 index 00000000..7425ef39 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/copyprep.cpp @@ -0,0 +1,426 @@ +#include "main.h" +#include "./copyfiles.h" +#include "./copyinternal.h" +#include "./resource.h" +#include "./settings.h" +#include "../nu/trace.h" +#include <shlwapi.h> +#include <strsafe.h> + +typedef struct _PREPDLG +{ + HFONT hfItalic; + HWND hActiveHelp; + HBITMAP hbmpLogo; + IAutoComplete *pac; + IACList2 *pacl2; + COPYDATA *pCopyData; + TCHAR szCurrentRoot[MAX_PATH]; +} PREPDLG; + +typedef struct _CALCDISKSIZE +{ + HWND hCallback; + DWORD dwError; + ULARGE_INTEGER bytesFree; + ULARGE_INTEGER bytesTotal; + TCHAR szRoot[MAX_PATH]; +} CALCDISKSIZE; + +#define PREPDLG_PROP TEXT("PREPDLG") +#define GetPrepDlg(__hdlg) ((PREPDLG*)GetProp((__hdlg), PREPDLG_PROP)) + +#define TID_UPDATEDISKSIZE 1985 +#define DELAY_UPDATEDISKSIZE 100 + +static void DisplayFormatExample(HWND hdlg, INT nItemId) +{ + TCHAR szBuffer[MAX_PATH*2], szFormat[MAX_PATH] = {0}; + + Settings_ReadString(C_COPY, CF_TITLEFMT, szFormat, ARRAYSIZE(szFormat)); + szBuffer[0] = TEXT('\0'); + FormatFileName(szBuffer, ARRAYSIZE(szBuffer), szFormat, 10, + TEXT("U2"), + TEXT("The Joshua Tree"), + TEXT("Exit"), + TEXT("Rock"), + TEXT("1987"), + TEXT("U2"), + TEXT("u2_The_Joshua_Tree.Mp3"), + TEXT("")); + SetDlgItemText(hdlg, nItemId, szBuffer); +} + +static DWORD WINAPI DiskFreeSpace_ThreadProc(LPVOID param) +{ + CALCDISKSIZE *pcs = (CALCDISKSIZE*)param; + if (!pcs) return 0; + pcs->dwError = 0; + SetLastError(0); + if (!GetDiskFreeSpaceEx(pcs->szRoot, &pcs->bytesFree, &pcs->bytesTotal, NULL)) + pcs->dwError = GetLastError(); + PostMessage(pcs->hCallback, CPM_UPDATEDISKSIZE, 0, (LPARAM)pcs); + return 0; +} + +static void CopyPrepare_UpdateMessage(HWND hdlg) +{ + TCHAR szBuffer[MAX_PATH*2] = {0}; + PREPDLG *ppd = GetPrepDlg(hdlg); + + szBuffer[0] = TEXT('\0'); + if (ppd && ppd->pCopyData) + { + TCHAR szPath[MAX_PATH] = {0}, szFormat[256] = {0}; + if (S_OK != Settings_ReadString(C_COPY, CF_PATH, szPath, ARRAYSIZE(szPath))) *szPath = TEXT('\0'); + else CleanupDirectoryString(szPath); + + if (1 == ppd->pCopyData->count) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COPY_PREP_MESSAGE_SINGLE_FILE, szFormat, ARRAYSIZE(szFormat)); + StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szFormat, PathFindFileName(ppd->pCopyData->ppszFiles[0]), szPath); + } + else + { + WASABI_API_LNGSTRINGW_BUF(IDS_COPY_PREP_MESSAGE_MULTIPLE_FILES, szFormat, ARRAYSIZE(szFormat)); + StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szFormat, ppd->pCopyData->count, szPath); + } + } + SetDlgItemText(hdlg, IDC_LBL_MESSAGE, szBuffer); +} + +HBITMAP CopyFiles_LoadResourcePng(LPCTSTR pszResource) +{ + HBITMAP hbmp; + MLIMAGESOURCE src = { sizeof(MLIMAGESOURCE), }; + src.lpszName = pszResource; + src.type = SRC_TYPE_PNG; + src.flags = 0; + + src.hInst = WASABI_API_LNG_HINST; + hbmp = MLImageLoader_LoadDib(plugin.hwndLibraryParent, &src); + if(!hbmp) + { + src.hInst = WASABI_API_ORIG_HINST; + hbmp = MLImageLoader_LoadDib(plugin.hwndLibraryParent, &src); + } + + DIBSECTION dibsec; + + if (hbmp && sizeof(DIBSECTION) == GetObjectW(hbmp, sizeof(DIBSECTION), &dibsec) && + BI_RGB == dibsec.dsBmih.biCompression && 1 == dibsec.dsBmih.biPlanes && 32 == dibsec.dsBm.bmBitsPixel) + { + MLIMAGEFILTERAPPLYEX filter = { sizeof(MLIMAGEFILTERAPPLYEX), }; + filter.filterUID = MLIF_BLENDONBK_UID; + filter.cx = dibsec.dsBm.bmWidth; + filter.cy = dibsec.dsBm.bmHeight; + filter.bpp = dibsec.dsBm.bmBitsPixel; + filter.pData = (LPBYTE)dibsec.dsBm.bmBits; + filter.rgbBk = GetSysColor(COLOR_3DFACE); + MLImageFilter_ApplyEx(plugin.hwndLibraryParent, &filter); + } + return hbmp; +} + +static INT_PTR CopyPrepare_OnInitDialog(HWND hdlg, HWND hFocus, LPARAM lParam) +{ + HWND hctrl; + PREPDLG *ppd = (PREPDLG*)calloc(1, sizeof(PREPDLG)); + if (!ppd) return 0; + + SetProp(hdlg, PREPDLG_PROP, ppd); + ppd->pCopyData = (COPYDATA*)lParam; + + hctrl = GetDlgItem(hdlg, IDOK); + if (hctrl) SendMessageW(hdlg, WM_NEXTDLGCTL, (WPARAM)hctrl, (LPARAM)TRUE); + SendMessageW(hdlg, WM_COMMAND, MAKEWPARAM(IDC_BTN_OPTIONS, BN_CLICKED), (LPARAM)GetDlgItem(hdlg, IDC_BTN_OPTIONS)); + + hctrl = GetDlgItem(hdlg, IDC_LBL_EXAMPLE); + if (hctrl) + { + LOGFONT lf; + HFONT hf = (HFONT)SendMessage(hctrl, WM_GETFONT, 0, 0L); + if (NULL == hf) hf = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + if (GetObject(hf, sizeof(LOGFONT), &lf)) + { + lf.lfItalic = TRUE; + ppd->hfItalic = CreateFontIndirect(&lf); + if (ppd->hfItalic) + { + UINT szIdList[] = { IDC_LBL_EXAMPLE_TITLE, IDC_LBL_EXAMPLE, IDC_LBL_FREE_TITLE, IDC_LBL_FREE, IDC_LBL_REQUIRED_TITLE, IDC_LBL_REQUIRED, }; + for (int i = 0; i < sizeof(szIdList)/sizeof(szIdList[0]); i++) SendDlgItemMessage(hdlg, szIdList[i], WM_SETFONT, (WPARAM)ppd->hfItalic, FALSE); + } + } + } + + if (ppd->pCopyData && ppd->pCopyData->pFSizes) + { + TCHAR szBuffer[128] = {0}; + ULONGLONG total = 0; + for(int i = 0; i < ppd->pCopyData->count; i++) total += ppd->pCopyData->pFSizes[i]; + StrFormatByteSize64(total, szBuffer, ARRAYSIZE(szBuffer)); + SetDlgItemText(hdlg, IDC_LBL_REQUIRED, szBuffer); + } + else + { + ShowWindow(GetDlgItem(hdlg, IDC_LBL_REQUIRED_TITLE), SW_HIDE); + ShowWindow(GetDlgItem(hdlg, IDC_LBL_REQUIRED), SW_HIDE); + } + + if (ppd->pCopyData && ppd->pCopyData->hOwner) + { + RECT rw; + if (!GetWindowRect(ppd->pCopyData->hOwner, &rw)) SetRect(&rw, 0, 0, 0, 0); + if (hdlg && rw.left != rw.right) + { + RECT rw2; + GetWindowRect(hdlg, &rw2); + SetWindowPos(hdlg, HWND_TOP, + rw.left + ((rw.right - rw.left) - (rw2.right - rw2.left))/2, + rw.top + ((rw.bottom - rw.top) - (rw2.bottom - rw2.top))/2, + 0, 0, SWP_NOACTIVATE | SWP_NOSIZE); + } + } + + CopyPrepare_UpdateMessage(hdlg); + + SendMessage(hdlg, DM_REPOSITION, 0, 0L); + + ppd->hbmpLogo = CopyFiles_LoadResourcePng(MAKEINTRESOURCE(IDB_FILECOPY)); + if (ppd->hbmpLogo) SendDlgItemMessage(hdlg, IDC_PIC_LOGO, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)ppd->hbmpLogo); + else ShowWindow(GetDlgItem(hdlg, IDC_PIC_LOGO), SW_HIDE); + + return FALSE; +} + +static void CopyPrepare_OnDestroy(HWND hdlg) +{ + PREPDLG *ppd = GetPrepDlg(hdlg); + RemoveProp(hdlg, PREPDLG_PROP); + if (ppd) + { + if (ppd->hActiveHelp) DestroyWindow(ppd->hActiveHelp); + if (ppd->hfItalic) DeleteObject(ppd->hfItalic); + if (ppd->pacl2) ppd->pacl2->Release(); + if (ppd->pac) ppd->pac->Release(); + + if (ppd->hbmpLogo) + { + HBITMAP hbmp = (HBITMAP)SendDlgItemMessage(hdlg, IDC_PIC_LOGO, STM_GETIMAGE, IMAGE_BITMAP, 0L); + if (hbmp != ppd->hbmpLogo) DeleteObject(hbmp); + DeleteObject(ppd->hbmpLogo); + } + free(ppd); + } +} +static void CopyPrepare_OnParentNotify(HWND hdlg, UINT uMsg, LPARAM lParam) +{ + PREPDLG *ppd = GetPrepDlg(hdlg); + if (ppd && WM_DESTROY == uMsg && ppd->hActiveHelp && ppd->hActiveHelp == (HWND)lParam) + ppd->hActiveHelp = NULL; +} + +static void CALLBACK CopyPrepare_OnUpdateDiskSizeTimer(HWND hdlg, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + KillTimer(hdlg, idEvent); + + CopyPrepare_UpdateMessage(hdlg); + + PREPDLG *ppd = GetPrepDlg(hdlg); + if (!ppd) return; + CALCDISKSIZE *pcs = (CALCDISKSIZE*)calloc(1, sizeof(CALCDISKSIZE)); + if (!pcs) return; + + pcs->hCallback = hdlg; + + if (S_OK == Settings_ReadString(C_COPY, CF_PATH, pcs->szRoot, ARRAYSIZE(pcs->szRoot))) + { + PathStripToRoot(pcs->szRoot); + + if (TEXT('\0') != *pcs->szRoot && + (TEXT('\0') == *ppd->szCurrentRoot || + CSTR_EQUAL != CompareString(STRCOMP_INVARIANT, NORM_IGNORECASE, ppd->szCurrentRoot, -1, pcs->szRoot, -1))) + { + DWORD threadId; + SetDlgItemText(hdlg, IDC_LBL_FREE, WASABI_API_LNGSTRINGW(IDS_CALCULATING)); + HANDLE ht = CreateThread(NULL, 0, DiskFreeSpace_ThreadProc, pcs, 0, &threadId); + if (NULL != ht) + { + CloseHandle(ht); + StringCchCopy(ppd->szCurrentRoot, ARRAYSIZE(ppd->szCurrentRoot), pcs->szRoot); + return; + } + SetDlgItemText(hdlg, IDC_LBL_FREE, TEXT("")); + } + } + if (TEXT('\0') == *pcs->szRoot) + { + pcs->dwError = ERROR_INVALID_NAME; + StringCchCopy(ppd->szCurrentRoot, ARRAYSIZE(ppd->szCurrentRoot), pcs->szRoot); + PostMessage(pcs->hCallback, CPM_UPDATEDISKSIZE, 0, (LPARAM)pcs); + return; + } + free(pcs); + + +} + +static void CopyPrepare_OnUpdateDiskSizeResult(HWND hdlg, CALCDISKSIZE *pcs) +{ + if (!pcs) return; + PREPDLG *ppd = GetPrepDlg(hdlg); + if (ppd && CSTR_EQUAL == CompareString(STRCOMP_INVARIANT, NORM_IGNORECASE, ppd->szCurrentRoot, -1, pcs->szRoot, -1)) + { + TCHAR szBuffer[128] = {0}; + szBuffer[0] = TEXT('\0'); + + if (ERROR_SUCCESS == pcs->dwError) StrFormatByteSize64(pcs->bytesFree.QuadPart, szBuffer, ARRAYSIZE(szBuffer)); + else WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN, szBuffer, sizeof(szBuffer)); + + SetDlgItemText(hdlg, IDC_LBL_FREE, szBuffer); + } + free(pcs); +} + + +static void CopyPrepare_OnOptionsClick(HWND hdlg) +{ + RECT rw, rw2; + BOOL bEnable; + INT height; + + PREPDLG *ppd = GetPrepDlg(hdlg); + + HWND hctrl = GetDlgItem(hdlg, IDC_GRP_OPTIONS); + if (!hctrl || !GetWindowRect(hctrl, &rw)) return; + + GetWindowRect(hdlg, &rw2); + OffsetRect(&rw, -rw2.left, -rw2.top); + + if (WS_DISABLED & GetWindowLongPtrW(hctrl, GWL_STYLE)) + { + height = rw.bottom + 8; + bEnable = TRUE; + Settings_SetDirectoryCtrl(C_COPY, CF_PATH, hdlg, IDC_EDT_PATH); + Settings_SetCheckBox(C_COPY, CF_ADDTOMLDB, hdlg, IDC_CHK_ADDTOMLDB); + Settings_SetCheckBox(C_COPY, CF_USETITLEFMT, hdlg, IDC_CHK_CUSTOMNAME); + Settings_SetDlgItemText(C_COPY, CF_TITLEFMT, hdlg, IDC_EDT_NAMEFORMAT); + SetDlgItemText(hdlg, IDC_BTN_OPTIONS, WASABI_API_LNGSTRINGW(IDS_OPTIONS_HIDE)); + + if (ppd && NULL == ppd->pac) + { + HRESULT hr; + hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, IID_IAutoComplete, (LPVOID*)&ppd->pac); + if (S_OK == hr) + { + IAutoComplete2 *pac2; + if (SUCCEEDED(ppd->pac->QueryInterface(IID_IAutoComplete2, (LPVOID*)&pac2))) + { + pac2->SetOptions(ACO_AUTOSUGGEST | ACO_AUTOAPPEND | 0x00000020/*ACF_UPDOWNKEYDROPSLIST*/); + pac2->Release(); + } + + hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_INPROC_SERVER, IID_IACList2, (LPVOID*)&ppd->pacl2); + if (S_OK == hr) ppd->pacl2->SetOptions(ACLO_FILESYSDIRS); + } + if(ppd->pac) ppd->pac->Init(GetDlgItem(hdlg, IDC_EDT_PATH), ppd->pacl2, NULL, NULL); + } + } + else + { + height = rw.top; + bEnable = FALSE; + SetDlgItemText(hdlg, IDC_BTN_OPTIONS, WASABI_API_LNGSTRINGW(IDS_OPTIONS_SHOW)); + } + + SetWindowPos(hdlg, NULL, 0, 0, rw2.right - rw2.left, height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); + EnableWindow(hctrl, bEnable); + + UINT szIdList[] = { IDC_EDT_PATH, IDC_BTN_BROWSE, IDC_CHK_ADDTOMLDB, + IDC_CHK_CUSTOMNAME, IDC_EDT_NAMEFORMAT, IDC_BTN_HELP, }; + + for (int i = 0; i < sizeof(szIdList)/sizeof(szIdList[0]); i++) EnableWindow(GetDlgItem(hdlg, szIdList[i]), bEnable); + if (bEnable && BST_UNCHECKED == IsDlgButtonChecked(hdlg, IDC_CHK_CUSTOMNAME)) + { + EnableWindow(GetDlgItem(hdlg, IDC_EDT_NAMEFORMAT), FALSE); + ShowWindow(GetDlgItem(hdlg, IDC_LBL_EXAMPLE), SW_HIDE); + ShowWindow(GetDlgItem(hdlg, IDC_LBL_EXAMPLE_TITLE), SW_HIDE); + } +} + +static INT_PTR CopyPrepare_OnHelp(HWND hdlg, HELPINFO *phi) +{ + PREPDLG *ppd = GetPrepDlg(hdlg); + if (ppd && 0 == (WS_DISABLED & GetWindowLongPtrW(GetDlgItem(hdlg, IDC_GRP_OPTIONS), GWL_STYLE))) + { + if (ppd->hActiveHelp) SetWindowPos(ppd->hActiveHelp, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + else ppd->hActiveHelp = MLDisc_ShowHelp(hdlg, MAKEINTRESOURCE(IDS_COPY_FILENAME_FORMAT_TITLE), + MAKEINTRESOURCE(IDS_COPY_FILENAME_FORMAT_CAPTION), MAKEINTRESOURCE(IDS_COPY_FILENAME_FORMAT), HF_ALLOWRESIZE); + SetWindowLongPtrW(hdlg, DWLP_MSGRESULT, TRUE); + return TRUE; + } + return FALSE; +} + +INT_PTR CALLBACK CopyPrepare_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return CopyPrepare_OnInitDialog(hdlg, (HWND)wParam, lParam); + case WM_DESTROY: CopyPrepare_OnDestroy(hdlg); break; + case WM_PARENTNOTIFY: CopyPrepare_OnParentNotify(hdlg, LOWORD(wParam), lParam); break; + case WM_HELP: return CopyPrepare_OnHelp(hdlg, (HELPINFO*)lParam); + case CPM_UPDATEDISKSIZE: CopyPrepare_OnUpdateDiskSizeResult(hdlg, (CALCDISKSIZE*)lParam); break; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + EndDialog(hdlg, LOWORD(wParam)); + break; + case IDC_BTN_BROWSE: if (HIWORD(wParam) == BN_CLICKED) Settings_BrowseForFolder(C_COPY, CF_PATH, hdlg, IDC_EDT_PATH); break; + case IDC_BTN_OPTIONS: if (HIWORD(wParam) == BN_CLICKED) CopyPrepare_OnOptionsClick(hdlg); break; + case IDC_CHK_ADDTOMLDB: if (BN_CLICKED == HIWORD(wParam)) Settings_FromCheckBox(C_COPY, CF_ADDTOMLDB, hdlg, IDC_CHK_ADDTOMLDB); break; + case IDC_CHK_CUSTOMNAME: + if (BN_CLICKED == HIWORD(wParam)) + { + Settings_FromCheckBox(C_COPY, CF_USETITLEFMT, hdlg, IDC_CHK_CUSTOMNAME); + BOOL bEnable = (BST_UNCHECKED != IsDlgButtonChecked(hdlg, IDC_CHK_CUSTOMNAME)); + EnableWindow(GetDlgItem(hdlg, IDC_EDT_NAMEFORMAT), bEnable); + ShowWindow(GetDlgItem(hdlg, IDC_LBL_EXAMPLE_TITLE), (bEnable) ? SW_SHOWNA : SW_HIDE); + ShowWindow(GetDlgItem(hdlg, IDC_LBL_EXAMPLE), (bEnable) ? SW_SHOWNA : SW_HIDE); + + } + break; + + case IDC_EDT_PATH: + if (EN_CHANGE == HIWORD(wParam)) + { + Settings_FromDirectoryCtrl(C_COPY, CF_PATH, hdlg, IDC_EDT_PATH); + SetTimer(hdlg, TID_UPDATEDISKSIZE, DELAY_UPDATEDISKSIZE, CopyPrepare_OnUpdateDiskSizeTimer); + } + break; + case IDC_EDT_NAMEFORMAT: + if (EN_CHANGE == HIWORD(wParam)) + { + Settings_FromDlgItemText(C_COPY, CF_TITLEFMT, hdlg, IDC_EDT_NAMEFORMAT); + DisplayFormatExample(hdlg, IDC_LBL_EXAMPLE); + } + break; + + case IDC_BTN_HELP: + if (HIWORD(wParam) == BN_CLICKED) + { + HELPINFO hi = {sizeof(HELPINFO), }; + hi.dwContextId = HELPINFO_WINDOW; + hi.iCtrlId = IDC_EDT_NAMEFORMAT; + hi.hItemHandle = GetDlgItem(hdlg, IDC_EDT_NAMEFORMAT); + hi.iContextType = 0; + hi.MousePos.x = 0; hi.MousePos.y = 0; + SendMessageW(hdlg, WM_HELP, 0, (LPARAM)&hi); + } + break; + } + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/copyprogress.cpp b/Src/Plugins/Library/ml_disc/copyprogress.cpp new file mode 100644 index 00000000..36bd36a7 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/copyprogress.cpp @@ -0,0 +1,360 @@ +#include "main.h" +#include "./copyfiles.h" +#include "./copyinternal.h" +#include "./resource.h" +#include "./settings.h" +#include "../nu/trace.h" +#include <shlwapi.h> +#include <strsafe.h> + +typedef struct _PROGDLG +{ + COPYDATA *pCopyData; + HBITMAP hbmpLogo; +} PROGDLG; + +#define PROGDLG_PROP TEXT("PROGDLG") +#define GetProgDlg(__hdlg) ((PROGDLG*)GetProp((__hdlg), PROGDLG_PROP)) + +#define SetControlText(__hwnd, __ctrlId, __pszText)\ + SetDlgItemText((__hwnd), (__ctrlId), (IS_INTRESOURCE(__pszText) ? WASABI_API_LNGSTRINGW((UINT)(UINT_PTR)(__pszText)) : (__pszText))) + +#define SetTaskText(__hwnd, __pszText) SetControlText(__hwnd, IDC_LBL_TASK, __pszText) +#define SetOperationText(__hwnd, __pszText) SetControlText(__hwnd, IDC_LBL_OPERATION, __pszText) + + +static INT_PTR CopyProgress_OnInitDialog(HWND hdlg, HWND hFocus, LPARAM lParam) +{ + HWND hctrl; + PROGDLG *ppd = (PROGDLG*)calloc(1, sizeof(PROGDLG)); + if (!ppd) return 0; + + SetProp(hdlg, PROGDLG_PROP, ppd); + ppd->pCopyData = (COPYDATA*)lParam; + CopyFiles_AddRef(ppd->pCopyData); + if (ppd->pCopyData && ppd->pCopyData->hOwner) + { + RECT rw; + if (!GetWindowRect(ppd->pCopyData->hOwner, &rw)) SetRect(&rw, 0, 0, 0, 0); + if (hdlg && rw.left != rw.right) + { + RECT rw2; + GetWindowRect(hdlg, &rw2); + SetWindowPos(hdlg, HWND_TOP, + rw.left + ((rw.right - rw.left) - (rw2.right - rw2.left))/2, + rw.top + ((rw.bottom - rw.top) - (rw2.bottom - rw2.top))/2, + 0, 0, SWP_NOACTIVATE | SWP_NOSIZE); + } + } + + hctrl = GetDlgItem(hdlg, IDC_PRG_TOTAL); + if (NULL != hctrl) + { + SendMessage(hctrl, PBM_SETRANGE32, (WPARAM)0, (LPARAM)100); + SendMessage(hctrl, PBM_SETPOS, (WPARAM)0, 0L); + SendMessage(hctrl, PBM_SETSTEP, (WPARAM)1, 0L); + } + + SetTaskText(hdlg, MAKEINTRESOURCE(IDS_COPY_TASK_PREPARE)); + SetOperationText(hdlg, TEXT("")); + + SendMessage(hdlg, DM_REPOSITION, 0, 0L); + + ppd->hbmpLogo = CopyFiles_LoadResourcePng(MAKEINTRESOURCE(IDB_FILECOPY)); + if (ppd->hbmpLogo) SendDlgItemMessage(hdlg, IDC_PIC_LOGO, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)ppd->hbmpLogo); + else ShowWindow(GetDlgItem(hdlg, IDC_PIC_LOGO), SW_HIDE); + + return FALSE; +} + +static void CopyProgress_OnDestroy(HWND hdlg) +{ + PROGDLG *ppd = GetProgDlg(hdlg); + RemoveProp(hdlg, PROGDLG_PROP); + if (ppd) + { + if (ppd->pCopyData) CopyFiles_Release(ppd->pCopyData); + + if (ppd->hbmpLogo) + { + HBITMAP hbmp = (HBITMAP)SendDlgItemMessage(hdlg, IDC_PIC_LOGO, STM_GETIMAGE, IMAGE_BITMAP, 0L); + if (hbmp != ppd->hbmpLogo) DeleteObject(hbmp); + DeleteObject(ppd->hbmpLogo); + } + + free(ppd); + } +} + +static void ShowErrorBox(HWND hdlg) +{ + PROGDLG *ppd = GetProgDlg(hdlg); + if (!ppd || !ppd->pCopyData) return; + + + TCHAR szBuffer[2048] = {0}, szFormat[256] = {0}, szUnknown[64] = {0}; + LPTSTR pszMessage; + + if (ERROR_REQUEST_ABORTED == ppd->pCopyData->errorCode) return; // ignore user aborts + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, + ppd->pCopyData->errorCode, 0, (LPTSTR)&pszMessage, 0, NULL); + + WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN, szUnknown, ARRAYSIZE(szUnknown)); + WASABI_API_LNGSTRINGW_BUF(IDS_COPY_ERROR_MESSAGE, szFormat, ARRAYSIZE(szFormat)); + + StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szFormat, + ppd->pCopyData->szDestination, + (ppd->pCopyData->errorMsgId) ? WASABI_API_LNGSTRINGW(ppd->pCopyData->errorMsgId) : szUnknown, + ppd->pCopyData->errorCode, + (pszMessage) ? pszMessage : szUnknown); + + MessageBox(hdlg, szBuffer, WASABI_API_LNGSTRINGW(IDS_COPY_ERROR_CAPTION), MB_OK | MB_ICONERROR); + if (pszMessage) LocalFree(pszMessage); +} + +static void CopyProgress_OnDisplayNextFile(HWND hdlg, INT iFile, INT iCount) +{ + PROGDLG *ppd = GetProgDlg(hdlg); + if (!ppd || !ppd->pCopyData) return; + SetOperationText(hdlg, PathFindFileName(ppd->pCopyData->ppszFiles[iFile])); + +} + + +static INT_PTR CopyProgress_OnDestiantionNotExist(HWND hdlg, LPCTSTR pszDestination) +{ + PROGDLG *ppd = GetProgDlg(hdlg); + if (!ppd || !ppd->pCopyData) return FALSE; + QUESTIONBOX qb = {0}; + TCHAR szFormat[MAX_PATH] = {0}, szMessage[MAX_PATH*2] = {0}; + + WASABI_API_LNGSTRINGW_BUF(IDS_DESTINATION_NOT_EXIST_FORMAT, szFormat, ARRAYSIZE(szFormat)); + StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szFormat, pszDestination); + + qb.hParent =hdlg; + qb.pszIcon = IDI_QUESTION; + qb.pszTitle = MAKEINTRESOURCE(IDS_CONFIRM_CREATE_DESTINATION); + qb.pszMessage = szMessage; + qb.pszBtnOkText = MAKEINTRESOURCE(IDS_YES); + qb.pszBtnCancelText = MAKEINTRESOURCE(IDS_NO); + qb.uBeepType = MB_ICONEXCLAMATION; + qb.uFlags = QBF_DEFAULT_OK | QBF_SETFOREGROUND | QBF_BEEP; + return (IDCANCEL == MLDisc_ShowQuestionBox(&qb)); +} + +static INT_PTR CopyProgress_OnReadOnly(HWND hdlg, LPCTSTR pszFile) +{ + PROGDLG *ppd = GetProgDlg(hdlg); + if (!ppd || !ppd->pCopyData) return FALSE; + QUESTIONBOX qb = {0}; + TCHAR szFormat[MAX_PATH] = {0}, szMessage[MAX_PATH*2] = {0}; + + WASABI_API_LNGSTRINGW_BUF(IDS_READONLY_FILE_DELETE_FORMAT, szFormat, ARRAYSIZE(szFormat)); + StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szFormat, pszFile); + + qb.hParent =hdlg; + qb.pszIcon = IDI_QUESTION; + qb.pszTitle = MAKEINTRESOURCE(IDS_CONFIRM_FILE_DELETE); + qb.pszMessage = szMessage; + qb.pszBtnOkText = MAKEINTRESOURCE(IDS_YES); + qb.pszBtnCancelText = MAKEINTRESOURCE(IDS_CANCEL); + qb.pszCheckboxText = MAKEINTRESOURCE(IDS_APPLY_TO_ALL_FILES); + qb.uBeepType = MB_ICONEXCLAMATION; + qb.uFlags = QBF_DEFAULT_OK | QBF_SETFOREGROUND | QBF_BEEP | QBF_SHOW_CHECKBOX; + + switch(MLDisc_ShowQuestionBox(&qb)) + { + case IDCANCEL: return READONLY_CANCELCOPY; + case IDOK: return (qb.checkboxChecked) ? READONLY_DELETEALL : READONLY_DELETE; + } + + return FALSE; +} + +static LPTSTR FormatFileInfo(LPTSTR pszBuffer, size_t cchBufferMax, LPCTSTR pszFilePath) +{ + HANDLE hFile; + HRESULT hr; + BY_HANDLE_FILE_INFORMATION fi; + + pszBuffer[0] = TEXT('\0'); + + hFile = CreateFile(pszFilePath, FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL,OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL); + + if (INVALID_HANDLE_VALUE != hFile && + GetFileInformationByHandle(hFile, &fi)) + { + TCHAR szTemp[1024] = {0}, szKeyword[64] = {0}; + SYSTEMTIME st = {0}; + + LONGLONG fsize = (LONGLONG)(((__int64)fi.nFileSizeHigh<< 32) | fi.nFileSizeLow); + + WASABI_API_LNGSTRINGW_BUF(IDS_SIZE, szKeyword, ARRAYSIZE(szKeyword)); + hr = StringCchPrintfEx(pszBuffer, cchBufferMax, &pszBuffer, &cchBufferMax, STRSAFE_IGNORE_NULLS, TEXT("\n %s: %s"), szKeyword, StrFormatByteSize64(fsize, szTemp, ARRAYSIZE(szTemp))); + + if (S_OK == hr && FileTimeToSystemTime(&fi.ftCreationTime, &st) && + GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szTemp, ARRAYSIZE(szTemp))) + { + WASABI_API_LNGSTRINGW_BUF(IDS_CREATED, szKeyword, ARRAYSIZE(szKeyword)); + hr = StringCchPrintfEx(pszBuffer, cchBufferMax, &pszBuffer, &cchBufferMax, STRSAFE_IGNORE_NULLS, TEXT("\n %s: %s"), szKeyword, szTemp); + if (S_OK == hr && GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szTemp, ARRAYSIZE(szTemp))) + hr = StringCchPrintfEx(pszBuffer, cchBufferMax, &pszBuffer, &cchBufferMax, STRSAFE_IGNORE_NULLS, TEXT(", %s"), szTemp); + + } + + + if (S_OK == hr && FileTimeToSystemTime(&fi.ftLastWriteTime, &st) && + GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szTemp, ARRAYSIZE(szTemp))) + { + WASABI_API_LNGSTRINGW_BUF(IDS_MODIFIED, szKeyword, ARRAYSIZE(szKeyword)); + hr = StringCchPrintfEx(pszBuffer, cchBufferMax, &pszBuffer, &cchBufferMax, STRSAFE_IGNORE_NULLS, TEXT("\n %s: %s"), szKeyword, szTemp); + if (S_OK == hr && GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szTemp, ARRAYSIZE(szTemp))) + hr = StringCchPrintfEx(pszBuffer, cchBufferMax, &pszBuffer, &cchBufferMax, STRSAFE_IGNORE_NULLS, TEXT(", %s"), szTemp); + + } + if (S_OK == hr) + { + hr = StringCchCopyEx(pszBuffer, cchBufferMax, TEXT("\n\n"), &pszBuffer, &cchBufferMax, STRSAFE_IGNORE_NULLS); + } + } + else hr = S_FALSE; + + if (S_OK != hr) pszBuffer[0] = TEXT('\0'); + + if (INVALID_HANDLE_VALUE != hFile) CloseHandle(hFile); + return pszBuffer; + +} +static INT_PTR CopyProgress_OnFileAlreadyExist(HWND hdlg, FILECONFLICT *pConflict) +{ + PROGDLG *ppd = GetProgDlg(hdlg); + if (!ppd || !ppd->pCopyData) return FALSE; + QUESTIONBOX qb = {0}; + TCHAR szFormat[128] = {0}, szMessage[MAX_PATH*2] = {0}, szPath[MAX_PATH] = {0}, szFileInfo1[128] = {0}, szFileInfo2[128] = {0}; + + WASABI_API_LNGSTRINGW_BUF(IDS_FILE_REPLACE_FORMAT, szFormat, ARRAYSIZE(szFormat)); + + StringCchCopy(szPath, ARRAYSIZE(szPath), pConflict->pszNameExisting); + LPTSTR pszFileName = PathFindFileName(szPath); + if (pszFileName && pszFileName > szPath) *(pszFileName - 1) = TEXT('\0'); + + FormatFileInfo(szFileInfo1, ARRAYSIZE(szFileInfo1), pConflict->pszNameExisting); + FormatFileInfo(szFileInfo2, ARRAYSIZE(szFileInfo2), pConflict->pszNameNew); + + StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szFormat, szPath, pszFileName, szFileInfo1, szFileInfo2); + + qb.hParent = hdlg; + qb.pszIcon = IDI_QUESTION; + qb.pszTitle = MAKEINTRESOURCE(IDS_CONFIRM_FILE_REPLACE); + qb.pszMessage = szMessage; + + qb.pszBtnExtraText = MAKEINTRESOURCE(IDS_SKIP); + qb.pszBtnOkText = MAKEINTRESOURCE(IDS_OVERWRITE); + qb.pszBtnCancelText = MAKEINTRESOURCE(IDS_CANCEL); + qb.pszCheckboxText = MAKEINTRESOURCE(IDS_APPLY_TO_ALL_FILES); + qb.uBeepType = MB_ICONEXCLAMATION; + + qb.uFlags = QBF_DEFAULT_OK | QBF_SETFOREGROUND | QBF_BEEP | QBF_SHOW_CHECKBOX | QBF_SHOW_EXTRA_BUTTON; + + INT_PTR qbr = MLDisc_ShowQuestionBox(&qb); + INT r = 0; + switch(qbr) + { + case IDCANCEL: r = EXISTFILE_CANCELCOPY; break; + case IDOK: r = EXISTFILE_OVERWRITE; break; + case IDC_BTN_EXTRA1: r = EXISTFILE_SKIP; break; + } + + if (qb.checkboxChecked) r |= EXISTFILE_APPLY_TO_ALL; + return r; +} + +static INT_PTR CopyProgress_OnCopyNotify(HWND hdlg, UINT uTask, UINT uOperation, LPARAM lParam) +{ + switch(uTask) + { + case CFT_INITIALIZING: + + switch(uOperation) + { + case CFO_INIT: + SetTaskText(hdlg, MAKEINTRESOURCE(IDS_COPY_TASK_PREPARE)); + SetOperationText(hdlg, TEXT("")); + break; + case CFO_CACLSIZE: + SetOperationText(hdlg, MAKEINTRESOURCE(IDS_COPY_OP_CALCULATESIZE)); + break; + case CFO_CHECKDESTINATION: + SetOperationText(hdlg, MAKEINTRESOURCE(IDS_COPY_OP_CHECKDESTINATION)); + break; + } + break; + case CFT_COPYING: + switch(uOperation) + { + case CFO_INIT: + SetTaskText(hdlg, MAKEINTRESOURCE(IDS_COPY_TASK_COPY)); + SetOperationText(hdlg, TEXT("")); + break; + case CFO_NEXTFILE: + CopyProgress_OnDisplayNextFile(hdlg, LOWORD(lParam), HIWORD(lParam)); + break; + case CFO_PROGRESS: + SendDlgItemMessage(hdlg, IDC_PRG_TOTAL, PBM_SETPOS, (WPARAM)lParam, 0L); + break; + } + break; + case CFT_FINISHED: + SetTaskText(hdlg, MAKEINTRESOURCE(IDS_COPY_TASK_FINISHED)); + switch(uOperation) + { + case CFO_SUCCESS: SetOperationText(hdlg, MAKEINTRESOURCE(IDS_COMPLETED)); break; + case CFO_CANCELLED: SetOperationText(hdlg, MAKEINTRESOURCE(IDS_CANCELLED)); break; + case CFO_FAILED: + SetOperationText(hdlg, MAKEINTRESOURCE(IDS_FAILED)); + ShowErrorBox(hdlg); + break; + } + DestroyWindow(hdlg); + break; + case CFT_CONFLICT: + switch(uOperation) + { + case CFO_DESTNOTEXIST: return CopyProgress_OnDestiantionNotExist(hdlg, (LPCTSTR)lParam); + case CFO_FILEALREDYEXIST: return CopyProgress_OnFileAlreadyExist(hdlg, (FILECONFLICT*)lParam); + case CFO_READONLY: return CopyProgress_OnReadOnly(hdlg, (LPCTSTR)lParam); + } + break; + } + return FALSE; +} +INT_PTR CALLBACK CopyProgress_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + PROGDLG *ppd = GetProgDlg(hdlg); + + switch(uMsg) + { + case WM_INITDIALOG: return CopyProgress_OnInitDialog(hdlg, (HWND)wParam, lParam); + case WM_DESTROY: CopyProgress_OnDestroy(hdlg); break; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + if (ppd && ppd->pCopyData) + { + SetOperationText(hdlg, MAKEINTRESOURCE(IDS_CANCELLING)); + SendDlgItemMessage(hdlg, IDCANCEL, BM_SETSTATE, (WPARAM)TRUE, 0L); + EnableWindow(GetDlgItem(hdlg, IDCANCEL), FALSE); + CopyFiles_CancelCopy(ppd->pCopyData); + } + else DestroyWindow(hdlg); + break; + } + case CFM_NOTIFY: MSGRESULT(hdlg, CopyProgress_OnCopyNotify(hdlg, LOWORD(wParam), HIWORD(wParam), lParam)); + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/discInfo.cpp b/Src/Plugins/Library/ml_disc/discInfo.cpp new file mode 100644 index 00000000..9aff366d --- /dev/null +++ b/Src/Plugins/Library/ml_disc/discInfo.cpp @@ -0,0 +1,328 @@ +#include "main.h" +#include "discinfo.h" +#include "resource.h" +#include <strsafe.h> + +// indices +#define DD_PARSED 0x0000 +#define DD_INDEX_MEDIUM_TYPE 0x0001 +#define DD_INDEX_MEDIUM_FORMAT 0x0002 +#define DD_INDEX_MEDIUM 0x0003 +#define DD_INDEX_PROTECTED_DVD 0x0004 +#define DD_INDEX_ERASABLE 0x0005 +#define DD_INDEX_TRACKS_NUM 0x0006 +#define DD_INDEX_SECTOR_USED 0x0007 +#define DD_INDEX_SECTOR_FREE 0x0008 + +#define TEXT_UNKNOWN L"Unknown" +#define TEXT_TRUE L"Yes" +#define TEXT_FALSE L"No" + +// MediumType Values +#define PRIMOSDK_SILVER 0x00000301 /* A disc that is not recordable. It may be a stamped (silver) disc or a gold (recordable) disc that has been recorded Disc-At-Once. */ +#define PRIMOSDK_COMPLIANTGOLD 0x00000302 /* A gold disc or rewritable disc that contains data but remains open, allowing the appending of additional data. */ +#define PRIMOSDK_OTHERGOLD 0x00000303 /* A gold disc to which it is not possible for PrimoSDK to append additional data. */ +#define PRIMOSDK_BLANK 0x00000304 /* A blank gold disc or blank rewritable disc. */ + +// MediumFormat Values +#define PRIMOSDK_B1 0x000000B1 /* Blank disc */ +#define PRIMOSDK_D1 0x000000D1 /* Data Mode 1 DAO (e.g. most data CD-ROMs or typical DOS games) */ +#define PRIMOSDK_D2 0x000000D2 /* Kodak Photo CD: Data multisession Mode 2 TAO */ +#define PRIMOSDK_D3 0x000000D3 /* Gold Data Mode 1: Data multisession Mode 1, closed */ +#define PRIMOSDK_D4 0x000000D4 /* Gold Data Mode 2: Data multisession Mode 2, closed */ +#define PRIMOSDK_D5 0x000000D5 /* Data Mode 2 DAO (silver mastered from Corel or Toast gold) */ +#define PRIMOSDK_D6 0x000000D6 /* CDRFS: Fixed packet (from Sony packet-writing solution) */ +#define PRIMOSDK_D7 0x000000D7 /* Packet writing */ +#define PRIMOSDK_D8 0x000000D8 /* Gold Data Mode 1: Data multisession Mode 1, open */ +#define PRIMOSDK_D9 0x000000D9 /* Gold Data Mode 2: Data multisession Mode 2, open */ +#define PRIMOSDK_A1 0x000000A1 /* Audio DAO/SAO/TAO (like most silver music discs) or closed gold audio */ +#define PRIMOSDK_A2 0x000000A2 /* Audio Gold disc with session not closed (TAO or SAO) */ +#define PRIMOSDK_A3 0x000000A3 /* First type of Enhanced CD (aborted) */ +#define PRIMOSDK_A4 0x000000A4 /* CD Extra, Blue Book standard */ +#define PRIMOSDK_A5 0x000000A5 /* Audio TAO with session not written (in-progress compilation) */ +#define PRIMOSDK_M1 0x000000E1 /* First track data, others audio */ +#define PRIMOSDK_M2 0x000000E2 /* Mixed-mode made TAO */ +#define PRIMOSDK_M3 0x000000E3 /* Kodak Portfolio (as per the Kodak standard) */ +#define PRIMOSDK_M4 0x000000E4 /* Video CD (as the White Book standard) */ +#define PRIMOSDK_M5 0x000000E5 /* CD-i (as the Green Book standard) */ +#define PRIMOSDK_M6 0x000000E6 /* PlayStation (Sony games) */ +#define PRIMOSDK_F1 0x000000F1 /* Obsolete */ +#define PRIMOSDK_F2 0x000000F2 /* Obsolete for restricted overwrite DVD (DLA DVD-RW) */ +#define PRIMOSDK_F3 0x000000F3 /* Completed (non-appendable) DVD (DVD-ROM or closed recordable) */ +#define PRIMOSDK_F4 0x000000F4 /* Incremental DVD with appendable zone (DLA DVD-R and DVD+RW) */ +#define PRIMOSDK_F8 0x000000F8 /* Appendable DVD of any type (single border or multiborder) */ +#define PRIMOSDK_FA 0x000000FA /* DVD-RAM cartridge */ +#define PRIMOSDK_GENERICCD 0x000000C1 /* Other type of CD. */ + +// Medium and Unit Values +#define PRIMOSDK_CDROM 0x00000201 /* CD-ROM */ +#define PRIMOSDK_CDR 0x00000202 /* CD-R */ +#define PRIMOSDK_CDRW 0x00000203 /* CD-RW */ +#define PRIMOSDK_DVDR 0x00000204 /* DVD-R */ +#define PRIMOSDK_DVDROM 0x00000205 /* DVD-ROM (any type) */ +#define PRIMOSDK_DVDRAM 0x00000206 /* DVD-RAM */ +#define PRIMOSDK_DVDRW 0x00000207 /* DVD-RW */ +#define PRIMOSDK_DVDPRW 0x00000209 /* DVD+RW */ +#define PRIMOSDK_DVDPR 0x00000210 /* DVD+R */ +#define PRIMOSDK_DDCDROM 0x00000211 /* Double-density CD-ROM */ +#define PRIMOSDK_DDCDR 0x00000212 /* Double-density CD-R */ +#define PRIMOSDK_DDCDRW 0x00000213 /* Double-density CD-RW */ +#define PRIMOSDK_DVDPR9 0x00000214 /* dual-layer DVD+R */ +#define PRIMOSDK_OTHER 0x00000220 /* other types */ + + +int mediumTypeText[] = {IDS_STAMPED_DISC_OR_RECORDABLE_THAT_HAS_BEEN_RECORDED, + IDS_REWRITEABLE_DISC_HAS_DATA_BUT_KEPT_OPEN_FOR_APPEND, + IDS_REWRITEABLE_DISC_NOT_POSSIBLE_TO_APPEND_DATA, + IDS_BLANK_REWRITEABLE_DISC, + }; + +const wchar_t *mediumText[] = {L"CD-ROM", L"CD-R", L"CD-RW", L"DVD-ROM", + L"DVD-R",L"DVD-RW", L"DVD+R", L"DVD+RW", L"DVD-RAM", + L"DDCD-ROM", L"DDCD-R", L"DDCD-RW", L"DL DVD+R"}; + +int mediumFormatText[] = { IDS_MEDIA_BLANK_DISC, + IDS_MEDIA_DATA_MODE_1_DAO, + IDS_MEDIA_KODAK_PHOTO_CD, + IDS_MEDIA_DATA_MULTISESSION_MODE_1_CLOSED, + IDS_MEDIA_DATA_MULTISESSION_MODE_2_CLOSED, + IDS_MEDIA_DATA_MODE_2_DAO, + IDS_MEDIA_CDRFS, + IDS_MEDIA_PACKET_WRITING, + IDS_MEDIA_DATA_MULTISESSION_MODE_1_OPEN, + IDS_MEDIA_DATA_MULTISESSION_MODE_2_OPEN, + IDS_MEDIA_AUDIO_DAO_SAO_TAO, + IDS_MEDIA_AUDIO_REWRITEABLE_DISC_WITH_SESSION_NOT_CLOSED, + IDS_MEDIA_FIRST_TYPE_OF_ENHANCED_CD_ABORTED, + IDS_MEDIA_CD_EXTRA, + IDS_MEDIA_AUDIO_TAO_WITH_SESSION_NOT_WRITTEN, + IDS_MEDIA_FIRST_TRACK_DATA_OTHERS_AUDIO, + IDS_MEDIA_MIXED_MODE_MADE_TAO, + IDS_MEDIA_KODAK_PORTFOLIO, + IDS_MEDIA_VIDEO_CD, + IDS_MEDIA_CDi, + IDS_MEDIA_PLAYSTATION_SONY_GAMES, + IDS_MEDIA_OBSOLETE, + IDS_MEDIA_OBSOLETE_FOR_RESTRICTED_OVERWRITE_DVD, + IDS_MEDIA_DVDROM_OR_CLOSED_RECORDABLE, + IDS_MEDIA_INCREMENTAL_DVD_WITH_APPENDABLE_ZONE, + IDS_MEDIA_APPENDABLE_DVD_OF_ANY_TYPE, + IDS_MEDIA_DVDRAM_CARTRIDGE, + IDS_MEDIA_CD_OTHER_TYPE + }; + +DiscInfo::DiscInfo(void) +{ + serialNum = 0; + memset(buffer, 0, sizeof(buffer)); + strData = NULL; + ResetData(); +} + +DiscInfo::DiscInfo(const wchar_t *info) +{ + serialNum = 0; + memset(buffer, 0, sizeof(buffer)); + strData = NULL; + SetStringInfo(info); +} + + +DiscInfo::~DiscInfo(void) +{ + ResetData(); +} + +void DiscInfo::ResetData(void) +{ + if (strData) free(strData); + strData = NULL; + + data[DD_PARSED]= FALSE; + for (int i = 1; i < DISC_DATA_COUNT; i++) data[i] = -1; +} + +BOOL DiscInfo::SetStringInfo(const wchar_t *info) +{ + ResetData(); + + int strLen = lstrlenW(info) + 1; + strData = (wchar_t*) malloc(strLen * sizeof(wchar_t)); + StringCchCopyW(strData, strLen, info); + + const wchar_t *start = info; + const wchar_t *end = info; + BOOL cont; + int i = 1; + do + { + while(end[0] != L';' && end[0] != 0x00) end = CharNextW(end); + cont = (end[0] == L';'); + + data[i++] = _wtoi(start); + + if(cont) + { + end = CharNextW(end); + start = end; + } + } + while(cont && i < DISC_DATA_COUNT); + + data[DD_PARSED] = (i == DISC_DATA_COUNT); + return data[DD_PARSED]; +} +const wchar_t* DiscInfo::GetStringInfo(void) +{ + return strData; +} +DWORD DiscInfo::GetMedium(void) +{ + return data[DD_INDEX_MEDIUM]; +} +DWORD DiscInfo::GetMediumType(void) +{ + return data[DD_INDEX_MEDIUM_TYPE]; +} +DWORD DiscInfo::GetMediumFormat(void) +{ + return data[DD_INDEX_MEDIUM_FORMAT]; +} +BOOL DiscInfo::GetProtectedDVD(void) +{ + return data[DD_INDEX_PROTECTED_DVD]; +} +BOOL DiscInfo::GetErasable(void) +{ + return data[DD_INDEX_ERASABLE]; +} +DWORD DiscInfo::GetTracksNumber(void) +{ + return data[DD_INDEX_TRACKS_NUM]; +} +DWORD DiscInfo::GetSectorsUsed(void) +{ + return data[DD_INDEX_SECTOR_USED]; +} +DWORD DiscInfo::GetSectorsFree(void) +{ + return data[DD_INDEX_SECTOR_FREE]; +} + +BOOL DiscInfo::GetRecordable(void) +{ + return (data[DD_INDEX_MEDIUM_TYPE] == PRIMOSDK_COMPLIANTGOLD || data[DD_INDEX_MEDIUM_TYPE] == PRIMOSDK_BLANK); +} + +int DiscInfo::GetSerialNumber(void) +{ + return serialNum; +} + +void DiscInfo::SetSerialNumber(int serialNumber) +{ + serialNum = serialNumber; +} + +const wchar_t* DiscInfo::GetMediumText(void) +{ + int index = -1; + switch(data[DD_INDEX_MEDIUM]) + { + case PRIMOSDK_CDROM: index = 0; break; + case PRIMOSDK_CDR: index = 1; break; + case PRIMOSDK_CDRW: index = 2; break; + case PRIMOSDK_DVDR: index = 4; break; + case PRIMOSDK_DVDROM: index = 3; break; + case PRIMOSDK_DVDRAM: index = 8; break; + case PRIMOSDK_DVDRW: index = 5; break; + case PRIMOSDK_DVDPRW: index = 7; break; + case PRIMOSDK_DVDPR: index = 6; break; + case PRIMOSDK_DDCDROM: index = 9; break; + case PRIMOSDK_DDCDR: index = 10; break; + case PRIMOSDK_DDCDRW: index = 11; break; + case PRIMOSDK_DVDPR9: index = 12; break; + default: return TEXT_UNKNOWN; + } + return mediumText[index]; +} +const wchar_t* DiscInfo::GetMediumTypeText(void) +{ + static wchar_t tmp[256]; + int index = -1; + switch(data[DD_INDEX_MEDIUM_TYPE]) + { + case PRIMOSDK_SILVER: index = 0; break; + case PRIMOSDK_COMPLIANTGOLD: index = 1; break; + case PRIMOSDK_OTHERGOLD: index = 2; break; + case PRIMOSDK_BLANK: index = 3; break; + default: return WASABI_API_LNGSTRINGW_BUF(plugin.hDllInstance,IDS_UNKNOWN,tmp,256); + } + return WASABI_API_LNGSTRINGW_BUF(plugin.hDllInstance,mediumTypeText[index],tmp,256); +} +const wchar_t* DiscInfo::GetMediumFormatText(void) +{ + static wchar_t tmpM[256]; + int index = -1; + switch(data[DD_INDEX_MEDIUM_FORMAT]) + { + case PRIMOSDK_B1: index = 0; break; + case PRIMOSDK_D1: index = 1; break; + case PRIMOSDK_D2: index = 2; break; + case PRIMOSDK_D3: index = 3; break; + case PRIMOSDK_D4: index = 4; break; + case PRIMOSDK_D5: index = 5; break; + case PRIMOSDK_D6: index = 6; break; + case PRIMOSDK_D7: index = 7; break; + case PRIMOSDK_D8: index = 8; break; + case PRIMOSDK_D9: index = 9; break; + case PRIMOSDK_A1: index = 10; break; + case PRIMOSDK_A2: index = 11; break; + case PRIMOSDK_A3: index = 12; break; + case PRIMOSDK_A4: index = 13; break; + case PRIMOSDK_A5: index = 14; break; + case PRIMOSDK_M1: index = 15; break; + case PRIMOSDK_M2: index = 16; break; + case PRIMOSDK_M3: index = 17; break; + case PRIMOSDK_M4: index = 18; break; + case PRIMOSDK_M5: index = 19; break; + case PRIMOSDK_M6: index = 20; break; + case PRIMOSDK_F1: index = 21; break; + case PRIMOSDK_F2: index = 22; break; + case PRIMOSDK_F3: index = 23; break; + case PRIMOSDK_F4: index = 24; break; + case PRIMOSDK_F8: index = 25; break; + case PRIMOSDK_FA: index = 26; break; + case PRIMOSDK_GENERICCD: index = 27; break; + default: return WASABI_API_LNGSTRINGW_BUF(plugin.hDllInstance,IDS_UNKNOWN,tmpM,256); + } + return WASABI_API_LNGSTRINGW_BUF(plugin.hDllInstance,mediumFormatText[index],tmpM,256); +} +const wchar_t* DiscInfo::GetProtectedDVDText(void) +{ + return data[DD_INDEX_PROTECTED_DVD] ? TEXT_TRUE : TEXT_FALSE ; +} +const wchar_t* DiscInfo::GetErasableText(void) +{ + return data[DD_INDEX_ERASABLE] ? TEXT_TRUE: TEXT_FALSE ; +} +const wchar_t* DiscInfo::GetTracksNumberText(void) +{ + StringCchPrintfW(buffer, TEXT_BUFFER_SIZE, L"%d", data[DD_INDEX_TRACKS_NUM]); + return buffer; +} +const wchar_t* DiscInfo::GetSectorsUsedText(void) +{ + StringCchPrintfW(buffer, TEXT_BUFFER_SIZE, L"%d", data[DD_INDEX_SECTOR_USED]); + return buffer; +} +const wchar_t* DiscInfo::GetSectorsFreeText(void) +{ + StringCchPrintfW(buffer, TEXT_BUFFER_SIZE, L"%d", data[DD_INDEX_SECTOR_FREE]); + return buffer; +} + +const wchar_t* DiscInfo::GetRecordableText(void) +{ + return GetRecordable() ? TEXT_TRUE : TEXT_FALSE; +} diff --git a/Src/Plugins/Library/ml_disc/discInfo.h b/Src/Plugins/Library/ml_disc/discInfo.h new file mode 100644 index 00000000..89f6d30e --- /dev/null +++ b/Src/Plugins/Library/ml_disc/discInfo.h @@ -0,0 +1,61 @@ +#ifndef NULLSOFT_DISCINFO_HEADER +#define NULLSOFT_DISCINFO_HEADER + +#include <windows.h> + + +// disc data array size (see decalrations in discInfo.cpp) +#define DISC_DATA_COUNT 0x0009 + +#define TEXT_BUFFER_SIZE 64 + + + +class DiscInfo +{ +public: + DiscInfo(void); + DiscInfo(const wchar_t *info); + ~DiscInfo(void); + +public: + + BOOL SetStringInfo(const wchar_t *info); + const wchar_t* GetStringInfo(void); + + DWORD GetMedium(void); + DWORD GetMediumType(void); + DWORD GetMediumFormat(void); + BOOL GetProtectedDVD(void); + BOOL GetErasable(void); + DWORD GetTracksNumber(void); + DWORD GetSectorsUsed(void); + DWORD GetSectorsFree(void); + void SetSerialNumber(int serialNumber); + int GetSerialNumber(void); + + BOOL GetRecordable(void); + + const wchar_t* GetMediumText(void); + const wchar_t* GetMediumTypeText(void); + const wchar_t* GetMediumFormatText(void); + const wchar_t* GetProtectedDVDText(void); + const wchar_t* GetErasableText(void); + const wchar_t* GetTracksNumberText(void); + const wchar_t* GetSectorsUsedText(void); + const wchar_t* GetSectorsFreeText(void); + + const wchar_t* GetRecordableText(void); + +protected: + void ResetData(void); + +private: + wchar_t *strData; + int serialNum; + wchar_t buffer[TEXT_BUFFER_SIZE]; + DWORD data[DISC_DATA_COUNT]; + +}; + +#endif // NULLSOFT_DISCINFO_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/drive.cpp b/Src/Plugins/Library/ml_disc/drive.cpp new file mode 100644 index 00000000..e38e9d4f --- /dev/null +++ b/Src/Plugins/Library/ml_disc/drive.cpp @@ -0,0 +1,138 @@ +#include "./main.h" +#include "./drive.h" +#include "./resource.h" +//#include <primosdk.h> +#include <strsafe.h> + +static LPCWSTR pszBusType[] = +{ + L"ATAPI", + L"SCSI", + L"1394", + L"USB", + L"USB2" +}; + +static LPCWSTR pszType[] = +{ + L"CD-ROM", + L"CD-R", + L"CD-RW", + L"DVD-ROM", + L"DVD-R", + L"DVD-RW", + L"DVD+R", + L"DVD+RW", + L"DVD-RAM", + L"DDCD-ROM", + L"DDCD-R", + L"DDCD-RW", + L"DL DVD+R", + L"DL DVD-R", + L"BD-RW", + L"BD-R", + L"BD-ROM", + L"HDDVD-RW", + L"HDDVD-R", + L"HDDVD-ROM", +}; + +static wchar_t buffer[64]; + +LPCWSTR Drive_GetBusTypeString(DWORD nBusType) +{ + int index = -1; +#if 0 + switch (nBusType) + { + case PRIMOSDK_ATAPI: index = 0; break; + case PRIMOSDK_SCSI: index = 1; break; + case PRIMOSDK_1394: index = 2; break; + case PRIMOSDK_USB: index = 3; break; + case PRIMOSDK_USB2: index = 4; break; + } +#endif + return (-1 != index) ? pszBusType[index] : + WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN, buffer, sizeof(buffer)/sizeof(wchar_t)); +} + +LPCWSTR Drive_GetTypeString(DWORD nType) +{ + int index = -1; +#if 0 + switch (nType) + { + case PRIMOSDK_CDROM: index = 0; break; + case PRIMOSDK_CDR: index = 1; break; + case PRIMOSDK_CDRW: index = 2; break; + case PRIMOSDK_DVDROM: index = 3; break; + case PRIMOSDK_DVDR: index = 4; break; + case PRIMOSDK_DVDRW: index = 5; break; + case PRIMOSDK_DVDPR: index = 6; break; + case PRIMOSDK_DVDPRW: index = 7; break; + case PRIMOSDK_DVDRAM: index = 8; break; + case PRIMOSDK_DDCDROM: index = 9; break; + case PRIMOSDK_DDCDR: index = 10; break; + case PRIMOSDK_DDCDRW: index = 11; break; + case PRIMOSDK_DVDPR9: index = 12; break; + case PRIMOSDK_DVDR9: index = 13; break; + case PRIMOSDK_BDRE: index = 14; break; + case PRIMOSDK_BDR: index = 15; break; + case PRIMOSDK_BDROM: index = 16; break; + case PRIMOSDK_HDDVDRW: index = 17; break; + case PRIMOSDK_HDDVDR: index = 18; break; + case PRIMOSDK_HDDVDROM: index = 19; break; + } +#endif + return (-1 != index) ? pszType[index] : + WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN, buffer, sizeof(buffer)/sizeof(wchar_t)); +} + +BOOL Drive_IsRecorderType(DWORD nType) +{ +#if 0 + switch(nType) + { + case PRIMOSDK_CDR: + case PRIMOSDK_CDRW: + case PRIMOSDK_DVDR: + case PRIMOSDK_DVDRW: + case PRIMOSDK_DVDPR: + case PRIMOSDK_DVDPRW: + case PRIMOSDK_DVDRAM: + case PRIMOSDK_DDCDR: + case PRIMOSDK_DDCDRW: + case PRIMOSDK_DVDPR9: + case PRIMOSDK_DVDR9: + case PRIMOSDK_BDRE: + case PRIMOSDK_BDR: + case PRIMOSDK_HDDVDRW: + case PRIMOSDK_HDDVDR: + return TRUE; + } +#endif + return FALSE; +} + +BOOL Drive_IsRecorder(CHAR cLetter) +{ +#if 0 + wchar_t info[128] = {0}; + wchar_t name[] = L"cda://X.cda"; + DWORD result; + BOOL reloaded = FALSE; + + name[6] = cLetter; + + for(;;) + { + result = getFileInfoW(name, L"cdinfo", info, sizeof(info)/sizeof(wchar_t)); + if (result || reloaded || !getFileInfoW(name, L"reloadsonic", NULL, 0)) break; + reloaded = TRUE; + } + + return (result) ? Drive_IsRecorderType(_wtoi(info)) : FALSE; +#else + return FALSE; +#endif +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/drive.h b/Src/Plugins/Library/ml_disc/drive.h new file mode 100644 index 00000000..3bfe5b92 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/drive.h @@ -0,0 +1,16 @@ +#ifndef NULLSOFT_MLDISC_DRIVE_HEADER +#define NULLSOFT_MLDISC_DRIVE_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + +LPCWSTR Drive_GetTypeString(DWORD nType); +LPCWSTR Drive_GetBusTypeString(DWORD nBusType); +BOOL Drive_IsRecorderType(DWORD nType); +BOOL Drive_IsRecorder(CHAR cLetter); + +#endif // NULLSOFT_MLDISC_DRIVE_HEADER + diff --git a/Src/Plugins/Library/ml_disc/driveListBox.cpp b/Src/Plugins/Library/ml_disc/driveListBox.cpp new file mode 100644 index 00000000..8f5fbdf3 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/driveListBox.cpp @@ -0,0 +1,255 @@ +#include "main.h" +#include ".\DriveListBox.h" +#include "resource.h" +#include "..\..\General\gen_ml\graphics.h" +#include <strsafe.h> + +DriveListBox::DriveListBox(int controlId) +{ + m_hwnd = NULL; + m_parentHwnd= NULL; + hInstance = NULL; + bmpNormal = NULL; + bmpSelected = NULL; + driveResId = NULL; + bgndResId = NULL; + + this->controlId = controlId; + + SetRect(&rcItem, 0,0,0,68); // hardcoded height + + clrNormalBG = RGB(0,0,0); + clrSelected1 = RGB(0,0,0); + clrSelected2 = RGB(255,255,255); + clrTextSel = RGB(255,255,255); + clrTextNorm = RGB(0,255,0); +} + +DriveListBox::~DriveListBox(void) +{ + DestroyImages(); +} + +void DriveListBox::DestroyImages(void) +{ + if (bmpNormal) DeleteObject(bmpNormal); + bmpNormal = NULL; + + if (bmpSelected) DeleteObject(bmpSelected); + bmpSelected = NULL; +} + +void DriveListBox::SetColors(COLORREF clrNormalBG, COLORREF clrSelected1, COLORREF clrSelected2, COLORREF clrTextSel, COLORREF clrTextNorm) +{ + this->clrNormalBG = clrNormalBG; + this->clrSelected1 = clrSelected1; + this->clrSelected2 = clrSelected2; + this->clrTextSel = clrTextSel; + this->clrTextNorm = clrTextNorm; + ReloadImages(); +} + +void DriveListBox::SetImages(HINSTANCE hInstance, int bgndResId, int driveResId) +{ + this->hInstance = hInstance; + this->bgndResId = bgndResId; + this->driveResId = driveResId; + ReloadImages(); +} + +HWND DriveListBox::GetHWND(void) +{ + return m_hwnd; +} + +void DriveListBox::ReloadImages(void) +{ + DestroyImages(); + if (!hInstance) return; + + HBITMAP bmpBck = NULL, bmpDrive = NULL; + if (bgndResId) + { + bmpBck = (HBITMAP)LoadImage(hInstance, MAKEINTRESOURCE(bgndResId), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); + if (bmpBck) bmpBck = PatchBitmapColors24(bmpBck, clrSelected1, clrSelected2, Filter1); + } + if (driveResId) + { + bmpDrive = (HBITMAP)LoadImage(hInstance, MAKEINTRESOURCE(driveResId), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); + } + + CreateBitmaps(bmpBck, bmpDrive); + if (bmpBck) DeleteObject(bmpBck); + if (bmpDrive) DeleteObject(bmpDrive); +} + +void DriveListBox::CreateBitmaps(HBITMAP bmpBck, HBITMAP bmpDrive) +{ + if (rcItem.right == 0 || rcItem.bottom == 0) return; + + HBITMAP bmpDriveMask = NULL; + if (bmpDrive) bmpDriveMask = CreateBitmapMask(bmpDrive, RGB(255, 0, 255)); + + HDC hdc = GetDC(m_hwnd); + HBITMAP bmp; + + for (int i = 0; i < 2; i++) + { + bmp = CreateCompatibleBitmap(hdc, rcItem.right, rcItem.bottom); + HDC memDstDC = CreateCompatibleDC (hdc); + HDC memSrcDC = CreateCompatibleDC (hdc); + HBITMAP obmp1 = (HBITMAP)SelectObject(memDstDC, bmp); + HBITMAP obmp2 = (HBITMAP)SelectObject(memSrcDC, bmpBck); + + if (i == 0 ) + { + for (int i = 0; i < rcItem.right; i++) + { + BitBlt(memDstDC, i, 0, 2, rcItem.bottom, memSrcDC, 0, 0, SRCCOPY); + } + } + else + { + HBRUSH hb = CreateSolidBrush(clrNormalBG); + FillRect(memDstDC, &rcItem, hb); + DeleteObject(hb); + } + + BITMAP bm; + GetObject(bmpDrive, sizeof(BITMAP), &bm); + RECT r1 = { + max(2, (rcItem.right - bm.bmWidth) / 2), + max(2, (rcItem.bottom - 16 - bm.bmHeight) / 2), + min(rcItem.right - 4, bm.bmWidth), + min(rcItem.bottom -18, bm.bmHeight) + }; + SelectObject(memSrcDC, bmpDriveMask); + BitBlt(memDstDC, r1.left, r1.top, r1.right, r1.bottom, memSrcDC, 0,0, SRCAND); + + SelectObject(memSrcDC, bmpDrive); + BitBlt(memDstDC, r1.left, r1.top, r1.right, r1.bottom, memSrcDC, 0,0, SRCPAINT); + + SelectObject(memDstDC, obmp1); + SelectObject(memSrcDC, obmp2); + + DeleteDC(memDstDC); + DeleteDC(memSrcDC); + if (i == 0) bmpSelected = bmp; + else bmpNormal = bmp; + } + + ReleaseDC(m_hwnd, hdc); + DeleteObject(bmpDriveMask); +} + +void DriveListBox::Init(HWND hwnd) +{ + m_hwnd = hwnd; + m_parentHwnd = GetParent(hwnd); +} + +int DriveListBox::HandleMsgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_DRAWITEM: + if (wParam == (WPARAM)controlId) DrawItem((DRAWITEMSTRUCT *)lParam); + break; + case WM_MEASUREITEM: + if (wParam == (WPARAM)controlId && MeasureItem((LPMEASUREITEMSTRUCT)lParam)) return 1; + break; + + case WM_CTLCOLORLISTBOX: + SetBkColor((HDC)wParam, clrNormalBG); + return NULL; + } + return FALSE; +} + +void DriveListBox::DrawItem(LPDRAWITEMSTRUCT di) +{ + if(di->CtlType == ODT_LISTBOX) + { + if (di->itemID == -1) return; + + RECT r; + r=di->rcItem; + + if (!bmpSelected || !bmpNormal || ((r.right - r.left) != rcItem.right)) + { + SetRect(&rcItem, 0,0,r.right - r.left, rcItem.bottom); + ReloadImages(); + } + + HBITMAP bmp; + int color; + if (di->itemState & ODS_SELECTED) + { + bmp = bmpSelected; + color = clrTextSel; + } + else + { + bmp = bmpNormal; + color = clrTextNorm; + } + + RECT rc; + GetClientRect(di->hwndItem, &rc); + + HRGN rgnW = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom); + // HRGN rgn = CreateRoundRectRgn(r.left +2, r.top + 2, r.right - 2, r.bottom -2, 10, 8); + HRGN rgn = CreateRectRgn(r.left +2, r.top + 2, r.right - 2, r.bottom -2); + + CombineRgn(rgn, rgn, rgnW, RGN_AND); + SelectClipRgn(di->hDC, rgn); + DeleteObject(rgn); + DeleteObject(rgnW); + + if (bmp) + { + HDC hdcbmp = CreateCompatibleDC(di->hDC); + HBITMAP obmp = (HBITMAP)SelectObject(hdcbmp,bmp); + StretchBlt(di->hDC, + r.left, + r.top, + rcItem.right, + rcItem.bottom, + hdcbmp, + 0, + 0, + rcItem.right, + rcItem.bottom, + SRCCOPY); + SelectObject(hdcbmp,obmp); + DeleteDC(hdcbmp); + } + + InflateRect(&r, -2, -2); + + if ( (di->itemState & ODS_SELECTED) && GetFocus() == di->hwndItem) + { + DrawFocusRect(di->hDC, &r); + } + + SetBkMode(di->hDC, TRANSPARENT); + SetTextColor(di->hDC, color); + + RECT textRect = {r.left + 2, r.bottom - 20, r.right - 2, r.bottom - 6}; + + wchar_t str[256] = {0}; + INT nType; + nType = 0xFFFF & ((DWORD)di->itemData >> 16); + StringCchPrintfW(str, 256, WASABI_API_LNGSTRINGW(IDS_X_DRIVE_X), + (nType) ? Drive_GetTypeString(nType) : L"", + (CHAR)(0xFF & di->itemData)); + DrawTextW(di->hDC, str,-1,&textRect,DT_BOTTOM|DT_SINGLELINE|DT_CENTER); + } + return; +} + +int DriveListBox::MeasureItem(LPMEASUREITEMSTRUCT mi) +{ + mi->itemHeight = rcItem.bottom; + return 1; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/driveListBox.h b/Src/Plugins/Library/ml_disc/driveListBox.h new file mode 100644 index 00000000..95d0c4e1 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/driveListBox.h @@ -0,0 +1,50 @@ +#ifndef NULLSOFT_DRIVE_COMBOBOX_HEADER +#define NULLSOFT_DRIVE_COMBOBOX_HEADER + +#include "windows.h" + +class DriveListBox +{ +public: + DriveListBox(int controlId); + ~DriveListBox(void); + +public: + void SetColors(COLORREF clrNormalBG, COLORREF clrSelected1, COLORREF clrSelected2, COLORREF clrTextSel, COLORREF clrTextNorm); + void SetImages(HINSTANCE hInstance, int bgndResId, int driveResId); + void Init(HWND hwnd); + int HandleMsgProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + void ReloadImages(void); + HWND GetHWND(void); + +private: + void DestroyImages(void); + void CreateBitmaps(HBITMAP bmpBck, HBITMAP bmpDrive); + + void DrawItem(LPDRAWITEMSTRUCT di); + int MeasureItem(LPMEASUREITEMSTRUCT mi); + +private: + + HWND m_hwnd, m_parentHwnd; + + HINSTANCE hInstance; + + HBITMAP bmpNormal; + HBITMAP bmpSelected; + + int driveResId; + int bgndResId; + + RECT rcItem; + + int controlId; + + COLORREF clrNormalBG; + COLORREF clrSelected1; + COLORREF clrSelected2; + COLORREF clrTextSel; + COLORREF clrTextNorm; +}; + +#endif // NULLSOFT_DRIVE_COMBOBOX_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/drivemngr.cpp b/Src/Plugins/Library/ml_disc/drivemngr.cpp new file mode 100644 index 00000000..b2d87fcc --- /dev/null +++ b/Src/Plugins/Library/ml_disc/drivemngr.cpp @@ -0,0 +1,1910 @@ +#include "main.h" +#include "./drivemngr.h" +#include "./primosdk_helper.h" +#include "./resource.h" +#include "../nu/trace.h" +#include "./dbt.h" +#include "./spti.h" +#include <setupapi.h> + +#include <imapi.h> +#include <strsafe.h> + +#define LISTENER_CLASSNAME L"MLDISCLISTENER" +#define LISTENER_WINDOWNAME L"" + +#define POLLMEDIUMCHANGE_INTERVAL 2000 +#define POLLMEDIUMVALIDATE_INTERVAL 6000 + +#define DMS_SUSPENDED 0x0000 +#define DMS_ACTIVE 0x0001 + +#define WM_EX_QUIT (WM_APP + 1) + +typedef struct _MEDIUMINFO_I +{ + UINT msLastPolled; // last time medium info was polled + UINT serialNumber; // medium serialnumber +} MEDIUMINFO_I; + +typedef struct _DRIVEINFO_I +{ + char cLetter; // drive letter + INT deviceNumber; // system assigned device number (unique till next reboot) + BOOL bMediumInserted; // if TRUE mediumInfo contains valid data + CHAR cMode; // drive mode + DWORD dwType; // drive type + LPWSTR pszDevName; // device name + HANDLE hThread; // device info thread + DWORD dwThreadId; + MEDIUMINFO_I mediumInfo; +} DRIVEINFO_I; + +typedef struct _DRIVEMNGR +{ + HWND hwndListener; + DMNPROC callback; + UINT fState; + CRITICAL_SECTION csLock; + + DRIVEINFO_I *pDrives; + INT nCount; + INT nAlloc; + + HANDLE hPollingThread; + DWORD dwPollingThread; +} DRIVEMNGR; + +typedef struct _DEVICEINFO +{ + CHAR cLetter; + LPWSTR pszDevName; + WCHAR szTargetPath[128]; + WCHAR szVolumeName[64]; + DWORD dwType; + INT deviceNumber; + INT opCode; +} DEVICEINFO; + +static DRIVEMNGR *pMngr = NULL; + + +static void CALLBACK APC_CheckDrives(ULONG_PTR param); +static void CALLBACK APC_IsMediumChanged(ULONG_PTR param); + +static void CALLBACK APC_GetUnitInfo(ULONG_PTR param); +static void CALLBACK APC_GetUnitInfo2(ULONG_PTR param); +static void CALLBACK APC_GetDiscInfoEx(ULONG_PTR param); +static void CALLBACK APC_GetDiscInfo2(ULONG_PTR param); +static void CALLBACK APC_GetTitle(ULONG_PTR param); +static void CALLBACK APC_DriveScan(ULONG_PTR param); +static void CALLBACK APC_GetMCIInfo(ULONG_PTR param); +static void CALLBACK APC_GetIMAPIInfo(ULONG_PTR param); +static void CALLBACK APC_Eject(ULONG_PTR param); + +static DWORD CALLBACK InfoThread(LPVOID param); + +static DWORD CALLBACK PollingThread(LPVOID param); + +static void CALLBACK PollMediumInfo(ULONG_PTR param); + +static LRESULT WINAPI ListenerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +static CHAR CheckLetter(CHAR cLetter) +{ + if (cLetter < 'A' || cLetter > 'Z') + { + if (cLetter >= 'a' && cLetter <= 'z') return (cLetter - 0x20); + return 0; + } + return cLetter; +} + +static LPCWSTR GetDeviceName(CHAR cLetter) +{ + LPCWSTR pszDevName; + if (!pMngr) return NULL; + pszDevName = NULL; + + EnterCriticalSection(&pMngr->csLock); + for (int i = 0; i < pMngr->nCount; i++) + { + if (pMngr->pDrives[i].cLetter == cLetter) + { + pszDevName = pMngr->pDrives[i].pszDevName; + break; + } + } + LeaveCriticalSection(&pMngr->csLock); + + return pszDevName; +} + +static BOOL IsPollingRequired(void) +{ + HKEY hKey; + LONG result; + BOOL bAutoRunEnabled; + + bAutoRunEnabled = FALSE; + + result = RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Cdrom"), &hKey); + if (ERROR_SUCCESS == result) + { + DWORD value; + DWORD size; + size = sizeof(DWORD); + result = RegQueryValueEx(hKey, TEXT("AutoRun"), NULL, NULL, (LPBYTE)&value, &size); + if (ERROR_SUCCESS == result) bAutoRunEnabled = (0 != value); + + RegCloseKey(hKey); + } + return !bAutoRunEnabled; + +} +static CHAR Drive_LetterFromMask(ULONG unitmask) +{ + char i; + for (i = 0; i < 26; ++i) + { + if (unitmask & 0x1) break; + unitmask = unitmask >> 1; + } + return (i + 'A'); +} + +static BOOL Drive_Add(DEVICEINFO *pDevInfo) +{ + DRIVEINFO_I *pDrive; + if (!pMngr) return FALSE; + + EnterCriticalSection(&pMngr->csLock); + + INT index, opCode; + + opCode = 0; + for (index = 0; index < pMngr->nCount && pMngr->pDrives[index].cLetter != pDevInfo->cLetter; index++); + if (index != pMngr->nCount) + { + pDrive = &pMngr->pDrives[index]; + if (pDrive->deviceNumber != pDevInfo->deviceNumber || pDrive->dwType != pDevInfo->dwType) opCode = 1; + } + else + { + if (pMngr->nCount == pMngr->nAlloc) + { + LPVOID data; + data = realloc(pMngr->pDrives, sizeof(DRIVEINFO_I)*(pMngr->nCount + 2)); + if (!data) + { + LeaveCriticalSection(&pMngr->csLock); + return FALSE; + } + pMngr->pDrives = (DRIVEINFO_I*)data; + pMngr->nAlloc += 2; + } + pDrive = &pMngr->pDrives[pMngr->nCount]; + pMngr->nCount++; + + ZeroMemory(pDrive, sizeof(DRIVEINFO_I)); + pDrive->cLetter = pDevInfo->cLetter; + opCode = 2; + } + + if (opCode) + { + pDrive->deviceNumber = pDevInfo->deviceNumber; + pDrive->dwType = pDevInfo->dwType; + if (pDrive->pszDevName) free(pDrive->pszDevName); + pDrive->pszDevName = _wcsdup(pDevInfo->pszDevName); + } + + LeaveCriticalSection(&pMngr->csLock); + + if (opCode && pMngr->callback) pMngr->callback((2 == opCode) ? DMW_DRIVEADDED : DMW_DRIVECHANGED, pDevInfo->cLetter); + + return TRUE; +} + +static BOOL Drive_Remove(CHAR cLetter) +{ + INT index; + BOOL bReportChanges; + if (!pMngr) return FALSE; + + EnterCriticalSection(&pMngr->csLock); + + bReportChanges = FALSE; + index = pMngr->nCount; + while (index-- && pMngr->pDrives[index].cLetter != cLetter); + + if (-1 != index) + { + if (pMngr->pDrives[index].pszDevName) free(pMngr->pDrives[index].pszDevName); + if (index != pMngr->nCount - 1) MoveMemory(&pMngr->pDrives[index], &pMngr->pDrives[index + 1], sizeof(DRIVEINFO_I)*(pMngr->nCount - index)); + pMngr->nCount--; + bReportChanges = TRUE; + } + LeaveCriticalSection(&pMngr->csLock); + + if (bReportChanges && pMngr->callback) pMngr->callback(DMW_DRIVEREMOVED, cLetter); + return TRUE; +} + +static HRESULT QueueInfoAPC(CHAR cLetter, PAPCFUNC pfnAPC, ULONG_PTR param) +{ + DWORD *pdwThreadId(NULL); + HRESULT hr(S_FALSE); + HANDLE *phThread(NULL); + static HANDLE hDrivesInfoThread = NULL; + + if (NULL == pMngr) return E_FAIL; + + EnterCriticalSection(&pMngr->csLock); + if (cLetter) + { + INT index = pMngr->nCount; + while (index-- && pMngr->pDrives[index].cLetter != cLetter); + if (-1 != index) + { + phThread = &pMngr->pDrives[index].hThread; + pdwThreadId = &pMngr->pDrives[index].dwThreadId; + } + } + else + { + phThread = &hDrivesInfoThread; + } + + if (phThread) + { + if (!*phThread) + { + DWORD tid; + *phThread = CreateThread(NULL, 0, InfoThread, NULL, 0, &tid); + if (pdwThreadId) *pdwThreadId = tid; + Sleep(100); + } + if (*phThread) + { + if (0 == QueueUserAPC(pfnAPC, *phThread, param)) + { + TRACE_LINE(TEXT("queue user apc failed")); + } + else hr = S_OK; + } + } + + LeaveCriticalSection(&pMngr->csLock); + + return hr; +} + +static BOOL Medium_Add(CHAR cLetter, DWORD serial) +{ + INT index; + if (!pMngr) return FALSE; + + EnterCriticalSection(&pMngr->csLock); + + index = pMngr->nCount; + while (index-- && pMngr->pDrives[index].cLetter != cLetter); + if (-1 != index) + { + pMngr->pDrives[index].bMediumInserted = TRUE; + pMngr->pDrives[index].mediumInfo.msLastPolled = 0; + pMngr->pDrives[index].mediumInfo.serialNumber = serial; + } + + LeaveCriticalSection(&pMngr->csLock); + + if (-1 != index) + { + if (-1 == serial) QueueInfoAPC(cLetter, APC_IsMediumChanged, (ULONG_PTR)cLetter); + if (pMngr->callback) pMngr->callback(DMW_MEDIUMARRIVED, cLetter); + } + + return TRUE; +} + +static BOOL Medium_Remove(CHAR cLetter) +{ + INT index; + if (!pMngr) return FALSE; + + EnterCriticalSection(&pMngr->csLock); + + index = pMngr->nCount; + while (index-- && pMngr->pDrives[index].cLetter != cLetter); + if (-1 != index) pMngr->pDrives[index].bMediumInserted = FALSE; + + LeaveCriticalSection(&pMngr->csLock); + + if (-1 != index && pMngr->callback) pMngr->callback(DMW_MEDIUMREMOVED, cLetter); + + return TRUE; +} + +BOOL DriveManager_Initialize(DMNPROC DMNProc, BOOL bSuspended) +{ + WNDCLASSW wc = {0}; + HINSTANCE hInstance; + + if (pMngr || !DMNProc) return FALSE; + + pMngr = (DRIVEMNGR*)calloc(1, sizeof(DRIVEMNGR)); + if (!pMngr) return FALSE; + + hInstance = GetModuleHandle(NULL); + + if (!GetClassInfoW(hInstance, LISTENER_CLASSNAME, &wc)) + { + wc.hInstance = hInstance; + wc.lpfnWndProc = ListenerWndProc; + wc.lpszClassName = LISTENER_CLASSNAME; + if (!RegisterClassW(&wc)) + { + DriveManager_Uninitialize(0); + return FALSE; + } + } + pMngr->hwndListener = CreateWindowW(LISTENER_CLASSNAME, LISTENER_WINDOWNAME, WS_DISABLED, 0,0,0,0, HWND_DESKTOP, NULL, hInstance, 0L); + if (!pMngr->hwndListener) + { + DriveManager_Uninitialize(0); + return FALSE; + } + InitializeCriticalSection(&pMngr->csLock); + pMngr->callback = DMNProc; + + return TRUE; +} + +BOOL DriveManager_Uninitialize(INT msExitWaitTime) +{ + if (pMngr) + { + WNDCLASSW wc; + HINSTANCE hInstance; + + if (pMngr->hwndListener) DestroyWindow(pMngr->hwndListener); + + hInstance = GetModuleHandle(NULL); + if (GetClassInfoW(hInstance, LISTENER_CLASSNAME, &wc)) UnregisterClassW(LISTENER_CLASSNAME, hInstance); + + EnterCriticalSection(&pMngr->csLock); + + for (int index =0; index < pMngr->nCount; index++) + { + if (pMngr->pDrives[index].hThread) + { + PostThreadMessage(pMngr->pDrives[index].dwThreadId, WM_EX_QUIT, 1, 0); + INT result = WaitForSingleObject(pMngr->pDrives[index].hThread, msExitWaitTime); + if (WAIT_TIMEOUT == result) TerminateThread(pMngr->pDrives[index].hThread, 1); + CloseHandle(pMngr->pDrives[index].hThread); + pMngr->pDrives[index].hThread = NULL; + } + } + LeaveCriticalSection(&pMngr->csLock); + + if (pMngr->hPollingThread) + { + PostThreadMessage(pMngr->dwPollingThread, WM_EX_QUIT, 1, 0); + INT result = WaitForSingleObject(pMngr->hPollingThread, msExitWaitTime); + if (WAIT_TIMEOUT == result) TerminateThread(pMngr->hPollingThread, 1); + CloseHandle(pMngr->hPollingThread); + pMngr->hPollingThread = NULL; + } + + EnterCriticalSection(&pMngr->csLock); + + if (pMngr->pDrives) + { + free(pMngr->pDrives); + } + + DRIVEMNGR *managerInstance = pMngr; + pMngr = NULL; + + LeaveCriticalSection(&managerInstance->csLock); + DeleteCriticalSection(&managerInstance->csLock); + + free(managerInstance); + + PrimoSDKHelper_Uninitialize(); + + } + return TRUE; +} + +BOOL DriveManager_Suspend(void) +{ + if (!pMngr) return FALSE; + + pMngr->fState = DMS_SUSPENDED; + if (pMngr->hPollingThread) + { + PostThreadMessage(pMngr->dwPollingThread, WM_EX_QUIT, 1, 0); + pMngr->hPollingThread = NULL; + } + return TRUE; +} + +BOOL DriveManager_Update(BOOL bAsync) +{ + if (bAsync) return (QueueInfoAPC(0, APC_DriveScan, 0) && QueueInfoAPC(0, PollMediumInfo, 0)); + else + { + APC_DriveScan(0); + QueueInfoAPC(0, PollMediumInfo, 0); + } + return TRUE; +} + +BOOL DriveManager_Resume(BOOL bUpdate) +{ + if (!pMngr) return FALSE; + pMngr->fState = DMS_ACTIVE; + + EnterCriticalSection(&pMngr->csLock); + for (int index =0; index < pMngr->nCount; index++) pMngr->pDrives[index].mediumInfo.msLastPolled = 0; + LeaveCriticalSection(&pMngr->csLock); + + APC_DriveScan(0); + QueueInfoAPC(0, PollMediumInfo, 0); + + if (NULL == pMngr->hPollingThread && IsPollingRequired()) + { + pMngr->hPollingThread = CreateThread(NULL, 0, PollingThread, NULL, 0, &pMngr->dwPollingThread); + } + + return TRUE; +} + +BOOL DriveManager_SetDriveMode(CHAR cLetter, CHAR cMode) +{ + BOOL report; + INT index; + + index = -1; + report = FALSE; + cLetter = CheckLetter(cLetter); + + if (pMngr && cLetter) + { + EnterCriticalSection(&pMngr->csLock); + for (index =0; index < pMngr->nCount; index++) + { + if (pMngr->pDrives[index].cLetter == cLetter) + { + if (pMngr->pDrives[index].cMode != cMode) + { + pMngr->pDrives[index].cMode = cMode; + report = TRUE; + } + break; + } + } + if (index == pMngr->nCount) index = -1; + LeaveCriticalSection(&pMngr->csLock); + if (report && pMngr->callback) pMngr->callback(DMW_MODECHANGED, MAKEWORD(cLetter, cMode)); + } + + return (-1 != index); +} + +CHAR DriveManager_GetDriveMode(CHAR cLetter) +{ + CHAR result; + + result = DM_MODE_ERROR; + cLetter = CheckLetter(cLetter); + + if (pMngr && cLetter) + { + INT index; + EnterCriticalSection(&pMngr->csLock); + for (index =0; index < pMngr->nCount; index++) + { + if (pMngr->pDrives[index].cLetter == cLetter) + { + result = pMngr->pDrives[index].cMode; + break; + } + } + LeaveCriticalSection(&pMngr->csLock); + } + return result; +} + +DWORD DriveManager_GetDriveType(CHAR cLetter) +{ + DWORD type; + + type = DRIVE_TYPE_UNKNOWN | DRIVE_CAP_UNKNOWN; + cLetter = CheckLetter(cLetter); + + if (pMngr && cLetter) + { + INT index; + EnterCriticalSection(&pMngr->csLock); + for (index =0; index < pMngr->nCount; index++) + { + if (pMngr->pDrives[index].cLetter == cLetter) + { + type = pMngr->pDrives[index].dwType; + break; + } + } + LeaveCriticalSection(&pMngr->csLock); + } + return type; +} + +BOOL DriveManager_IsMediumInserted(CHAR cLetter) +{ + BOOL result; + + result = FALSE; + cLetter = CheckLetter(cLetter); + + if (pMngr && cLetter) + { + INT index; + EnterCriticalSection(&pMngr->csLock); + for (index =0; index < pMngr->nCount; index++) + { + if (pMngr->pDrives[index].cLetter == cLetter) + { + result = pMngr->pDrives[index].bMediumInserted; + break; + } + } + LeaveCriticalSection(&pMngr->csLock); + } + return result; +} + +INT DriveManager_GetDriveList(CHAR *pLetters, INT cchSize) +{ + INT r = 0; + if (!pLetters || !pMngr) return -1; + EnterCriticalSection(&pMngr->csLock); + for (int index =0; index < pMngr->nCount; index++) + { + *pLetters = pMngr->pDrives[index].cLetter; + pLetters++; + cchSize--; + r++; + if (0 == cchSize) break; + } + LeaveCriticalSection(&pMngr->csLock); + return r; +} + +static BOOL QueueInfoJob(PAPCFUNC pfnAPC, DM_NOTIFY_PARAM *pHeader) +{ + BOOL result(TRUE); + if (!pMngr || !pHeader) result = FALSE; + + if (result) + { + HANDLE hProc = GetCurrentProcess(); + pHeader->hReserved = 0; + result = (BOOL)DuplicateHandle(hProc, GetCurrentThread(), hProc, &pHeader->hReserved, + 0, FALSE, DUPLICATE_SAME_ACCESS); + if (!result) pHeader->hReserved = 0; + } + + if (result) + { + CHAR cLetter = CheckLetter(pHeader->cLetter); + result = (cLetter && S_OK == QueueInfoAPC(cLetter, pfnAPC, (ULONG_PTR)pHeader)); + } + + if(!result && pHeader && pHeader->fnFree) + { + if (pHeader->hReserved) CloseHandle(pHeader->hReserved); + pHeader->fnFree(pHeader); + } + return result; +} + +BOOL DriveManager_GetUnitInfo(DM_UNITINFO_PARAM *puip) +{ + return QueueInfoJob(APC_GetUnitInfo, (DM_NOTIFY_PARAM*)puip); +} + +BOOL DriveManager_GetUnitInfo2(DM_UNITINFO2_PARAM *puip) +{ + return QueueInfoJob(APC_GetUnitInfo2, (DM_NOTIFY_PARAM*)puip); +} + +BOOL DriveManager_GetDiscInfoEx(DM_DISCINFOEX_PARAM *pdip) +{ + return QueueInfoJob(APC_GetDiscInfoEx, (DM_NOTIFY_PARAM*)pdip); +} +BOOL DriveManager_GetDiscInfo2(DM_DISCINFO2_PARAM *pdip) +{ + return QueueInfoJob(APC_GetDiscInfo2, (DM_NOTIFY_PARAM*)pdip); +} + +BOOL DriveManager_QueryTitle(DM_TITLE_PARAM *pdtp) +{ + return QueueInfoJob(APC_GetTitle, (DM_NOTIFY_PARAM*)pdtp); +} + +BOOL DriveManager_GetMCIInfo(DM_MCI_PARAM *pmcip) +{ + return QueueInfoJob(APC_GetMCIInfo, (DM_NOTIFY_PARAM*)pmcip); +} + +BOOL DriveManager_GetIMAPIInfo(DM_IMAPI_PARAM *pIMAPI) +{ + return QueueInfoJob(APC_GetIMAPIInfo, (DM_NOTIFY_PARAM*)pIMAPI); +} +BOOL DriveManager_Eject(CHAR cLetter, INT nCmd) +{ + if (!pMngr) return FALSE; + CHAR cLetter1 = CheckLetter(cLetter); + + return (cLetter1 && QueueInfoAPC(cLetter1, APC_Eject, (ULONG_PTR)MAKELONG(cLetter, nCmd))); +} + +BOOL DriveManager_IsUnitReady(CHAR cLetter, BOOL *pbReady) +{ + BYTE sc, asc, ascq; + + BOOL bSuccess; + HANDLE hDevice; + + *pbReady = FALSE; + hDevice = CreateFileW(GetDeviceName(cLetter), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); + + if (INVALID_HANDLE_VALUE == hDevice) return FALSE; + + bSuccess = SPTI_TestUnitReady(hDevice, &sc, &asc, &ascq, 3); + if (!bSuccess) + { + if (ERROR_SEM_TIMEOUT == GetLastError()) bSuccess = TRUE; + } + else if (0x00 == sc || (0x02 == sc && 0x3A == asc)) *pbReady = TRUE; + + CloseHandle(hDevice); + + return bSuccess; +} + +static BOOL GetVolumeNameForVolumeMountPoint_DL(LPCWSTR lpszVolumeMountPoint, LPWSTR lpszVolumeName, DWORD cchBufferLength) +{ + static BOOL (WINAPI *func)(LPCWSTR, LPWSTR, DWORD) = NULL; + if (!func) + { + UINT prevErrorMode; + HMODULE hModule; + prevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); + hModule = LoadLibraryW(L"Kernel32.dll"); + SetErrorMode(prevErrorMode); + if (hModule) + { + func = (BOOL (WINAPI*)(LPCWSTR, LPWSTR, DWORD))GetProcAddress(hModule, "GetVolumeNameForVolumeMountPointW"); + FreeLibrary(hModule); + } + } + return (func) ? func(lpszVolumeMountPoint, lpszVolumeName, cchBufferLength) : FALSE; +} + +static DWORD GetDeviceNames(DEVICEINFO *pDevInfo, INT count) +{ + HANDLE hDevInfo; + SP_DEVICE_INTERFACE_DATA spiData; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *pspiDetailData; + DWORD dwErrorCode, dwReqSize, dwDetailSize; + wchar_t volume[128], szDosName[] = L"X:\\", szDosName1[] = L"X:\\"; + + if (!pDevInfo || !count) return ERROR_INVALID_DATA; + + for (int i = 0; i < count; i++) + { + szDosName[0] = pDevInfo[i].cLetter; + GetVolumeNameForVolumeMountPoint_DL(szDosName, pDevInfo[i].szVolumeName, sizeof(pDevInfo[i].szVolumeName)/sizeof(wchar_t)); + szDosName1[0] = pDevInfo[i].cLetter; + QueryDosDeviceW(szDosName1, pDevInfo[i].szTargetPath, sizeof(pDevInfo[i].szTargetPath)/sizeof(wchar_t)); + } + + hDevInfo = SetupDiGetClassDevs((LPGUID)&CdRomClassGuid, NULL, NULL, (DIGCF_PRESENT | DIGCF_INTERFACEDEVICE)); + if (INVALID_HANDLE_VALUE == hDevInfo) return GetLastError(); + + dwDetailSize = 0; + pspiDetailData = NULL; + spiData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + dwErrorCode = 0; + + for (int index = 0; !dwErrorCode; index++) + { + BOOL bResult = SetupDiEnumDeviceInterfaces(hDevInfo, 0, (LPGUID)&CdRomClassGuid, index, &spiData); + if (!bResult) + { + dwErrorCode = GetLastError(); + break; + } + + bResult = SetupDiGetDeviceInterfaceDetailW(hDevInfo, &spiData, NULL, 0, &dwReqSize, NULL); + if (!bResult) + { + dwErrorCode = GetLastError(); + if (ERROR_INSUFFICIENT_BUFFER != dwErrorCode) break; + dwErrorCode = 0; + } + dwReqSize += 2*sizeof(wchar_t); + if (dwReqSize > dwDetailSize) + { + LPVOID data; + data = realloc(pspiDetailData, dwReqSize); + if (!data) { dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; break; } + pspiDetailData = (SP_DEVICE_INTERFACE_DETAIL_DATA*)data; + dwDetailSize = dwReqSize; + } + + pspiDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + bResult = SetupDiGetDeviceInterfaceDetailW(hDevInfo, &spiData, pspiDetailData, dwDetailSize, NULL, NULL); + if (!bResult) + { + dwErrorCode = GetLastError(); + break; + } + + INT cchName; + cchName = lstrlenW(pspiDetailData->DevicePath); + pspiDetailData->DevicePath[cchName] = L'\\'; + pspiDetailData->DevicePath[cchName + 1] = 0x00; + + if(GetVolumeNameForVolumeMountPoint_DL(pspiDetailData->DevicePath, volume, sizeof(volume)/sizeof(wchar_t))) + { + for (int i = 0; i < count; i++) + { + if (!pDevInfo[i].pszDevName && 0 == lstrcmpW(volume, pDevInfo[i].szVolumeName)) + { + pDevInfo[i].pszDevName = (LPWSTR)calloc((cchName + 1), sizeof(wchar_t)); + if (pDevInfo[i].pszDevName) StringCchCopyNW(pDevInfo[i].pszDevName, cchName + 1, pspiDetailData->DevicePath, cchName); + break; + } + } + } + } + if (pspiDetailData) free(pspiDetailData); + SetupDiDestroyDeviceInfoList(hDevInfo); + + for (int i = 0; i < count; i++) + { + if (!pDevInfo[i].pszDevName) + { + wchar_t szDevName[] = L"\\\\.\\x:"; + szDevName[4] = pDevInfo[i].cLetter; + pDevInfo[i].pszDevName = (LPWSTR)calloc(sizeof(szDevName) + 2, sizeof(wchar_t)); + if (pDevInfo[i].pszDevName) StringCbCopyW(pDevInfo[i].pszDevName, sizeof(szDevName) + 2, szDevName); + } + } + + return dwErrorCode; +} + +static void GetDeviceCaps(DEVICEINFO *pDevInfo, INT count) +{ + for( int i = 0; i < count; i++) + { + pDevInfo[i].dwType = ((pDevInfo[i].dwType & 0x0000FFFF) | DRIVE_CAP_UNKNOWN); + } + + // TODO come back to this later on, but for the moment not seeing any noticeable issues + // with disabling this and instead and instead it helps prevent random trk****.tmp + // files being generated and also seems to fix the crash on start people have here + /*IDiscMaster *pdm; + IDiscRecorder *pdr; + IEnumDiscRecorders *per; + ULONG nActual; + HRESULT hr = CoCreateInstance(CLSID_MSDiscMasterObj, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IDiscMaster, (void**)&pdm); + if (SUCCEEDED(hr)) + { + // TODO determine why this is causing trk*.tmp files to be created when called + // which ends up spamming the %temp% folder everytime Winamp starts :o( + hr = pdm->Open(); + if (SUCCEEDED(hr)) + { + IEnumDiscMasterFormats *pef; + hr = pdm->EnumDiscMasterFormats(&pef); + if (SUCCEEDED(hr)) + { + IID pFormats[2]; + hr = pef->Next(sizeof(pFormats)/sizeof(IID), pFormats, &nActual); + if (SUCCEEDED(hr)) + { + while(nActual--) { if (IID_IRedbookDiscMaster == pFormats[nActual]) break; } + if (nActual != ((ULONG)-1)) + { + IRedbookDiscMaster *pdf; + hr = pdm->SetActiveDiscMasterFormat(IID_IRedbookDiscMaster, (void**)&pdf); + if (SUCCEEDED(hr)) + { + pdf->Release(); + hr = pdm->EnumDiscRecorders(&per); + if (SUCCEEDED(hr)) + { + while (S_OK== per->Next(1, &pdr, &nActual) && nActual > 0) + { + BSTR bstrPath; + hr = pdr->GetPath(&bstrPath); + if (SUCCEEDED(hr)) + { + for (int i = 0; i < count; i++) + { + if (0 == lstrcmpW(pDevInfo[i].szTargetPath, bstrPath)) + { + LONG type; + if (SUCCEEDED(pdr->GetRecorderType(&type))) + { + pDevInfo[i].dwType &= 0x0000FFFF; + switch(type) + { + case RECORDER_CDR: pDevInfo[i].dwType |= DRIVE_CAP_R; break; + case RECORDER_CDRW: pDevInfo[i].dwType |= DRIVE_CAP_RW; break; + } + } + break; + } + } + if (bstrPath) SysFreeString(bstrPath); + } + pdr->Release(); + } + per->Release(); + } + } + } + } + pef->Release(); + } + pdm->Close(); + } + pdm->Release(); + } + else + { + }*/ +} + +static void Listener_OnDeviceChange(HWND hwnd, UINT nType, DWORD_PTR dwData) +{ + DEV_BROADCAST_HDR *phdr; + + switch(nType) + { + case DBT_DEVICEARRIVAL: + phdr = (DEV_BROADCAST_HDR*)dwData; + if (DBT_DEVTYP_VOLUME == phdr->dbch_devicetype) + { + DEV_BROADCAST_VOLUME *pvol = (DEV_BROADCAST_VOLUME*)phdr; + if (DBTF_MEDIA == pvol->dbcv_flags) Medium_Add(Drive_LetterFromMask(pvol->dbcv_unitmask), (DWORD)-1); + else if (0 == pvol->dbcv_flags) + { + char root[] = "X:\\"; + root[0] = Drive_LetterFromMask(pvol->dbcv_unitmask); + if (DRIVE_CDROM == GetDriveTypeA(root)) QueueInfoAPC(0, APC_CheckDrives, (ULONG_PTR)root[0]); + } + } + break; + case DBT_DEVICEREMOVECOMPLETE: + phdr = (DEV_BROADCAST_HDR*)dwData; + if (DBT_DEVTYP_VOLUME == phdr->dbch_devicetype) + { + DEV_BROADCAST_VOLUME *pvol = (DEV_BROADCAST_VOLUME*)phdr; + if (DBTF_MEDIA == pvol->dbcv_flags) Medium_Remove(Drive_LetterFromMask(pvol->dbcv_unitmask)); + else if (0 == pvol->dbcv_flags) + { + char root[] = "X:\\"; + root[0] = Drive_LetterFromMask(pvol->dbcv_unitmask); + if (DRIVE_CDROM == GetDriveTypeA(root)) Drive_Remove(root[0]); + } + } + break; + } +} + +static DWORD CALLBACK InfoThread(LPVOID param) +{ + MSG msg; + DWORD start, status, timeout, result(0); + BOOL bComInit, run(TRUE); + HANDLE hTemp(NULL); + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); + bComInit = ( S_OK == CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); + + timeout = 20000; // 20 seconds delay + start = GetTickCount(); + + while(run) + { + DWORD elapsed = GetTickCount() - start; + if (elapsed < timeout) + status = MsgWaitForMultipleObjectsEx(0, NULL, timeout - elapsed, + QS_ALLINPUT, MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); + else status = WAIT_TIMEOUT; + + switch(status) + { + case WAIT_FAILED: + if (bComInit) CoUninitialize(); + return (DWORD)-1; + case WAIT_TIMEOUT: + if (NULL != pMngr) + { + EnterCriticalSection(&pMngr->csLock); + start = GetCurrentThreadId(); + hTemp = NULL; + + for (int i = pMngr->nCount - 1; i >= 0; i--) + { + if (pMngr->pDrives[i].dwThreadId == start) + { + pMngr->pDrives[i].dwThreadId = 0; + hTemp = pMngr->pDrives[i].hThread; + pMngr->pDrives[i].hThread = NULL; + } + } + LeaveCriticalSection(&pMngr->csLock); + + //while (WAIT_IO_COMPLETION == WaitForMultipleObjectsEx(0, NULL, TRUE, 0, TRUE)); + while (SleepEx(0, TRUE) == WAIT_IO_COMPLETION); + } + result = 2; + run = FALSE; + break; + case WAIT_IO_COMPLETION: start = GetTickCount(); break; + case WAIT_OBJECT_0: + while (run && PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + switch(msg.message) + { + case WM_QUIT: + result = (DWORD)msg.wParam; + run = FALSE; + break; + case WM_EX_QUIT: + PostQuitMessage((INT)msg.wParam); + break; + default: + TranslateMessage(&msg); + DispatchMessageW(&msg); + break; + } + } + break; + } + } + + if (bComInit) CoUninitialize(); + if (2 == result && hTemp) CloseHandle(hTemp); + hTemp = NULL; + return result; +} + +static DWORD CALLBACK PollingThread(LPVOID param) +{ + MSG msg; + DWORD status, timeout; + BOOL bComInit; + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE); + bComInit = ( S_OK == CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); + + timeout = POLLMEDIUMCHANGE_INTERVAL; + + for(;;) + { + DWORD elapsed, start = GetTickCount(); + while ((elapsed = GetTickCount() - start) < timeout) + { + status = MsgWaitForMultipleObjectsEx(0, NULL, timeout - elapsed, + QS_ALLINPUT, MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); + switch(status) + { + case WAIT_FAILED: + if (bComInit) CoUninitialize(); + return (DWORD)-1; + case WAIT_TIMEOUT: PollMediumInfo(0); break; + case WAIT_OBJECT_0: + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + switch(msg.message) + { + case WM_QUIT: + if (bComInit) CoUninitialize(); + return (DWORD)msg.wParam; + case WM_EX_QUIT: + PostQuitMessage((INT)msg.wParam); + break; + default: + TranslateMessage(&msg); + DispatchMessageW(&msg); + break; + } + } + break; + } + } + } +} + +static void CALLBACK PollMediumInfo(ULONG_PTR param) +{ + char letters[32] = {0}; + LPCWSTR pszDevName[32] = {0}; + INT index, count; + if (!pMngr) return; + + count = 0; + EnterCriticalSection(&pMngr->csLock); + for (index =0; index < pMngr->nCount; index++) + { + if (DM_MODE_BURNING != pMngr->pDrives[index].cMode && DM_MODE_RIPPING != pMngr->pDrives[index].cMode) + { + letters[count] = pMngr->pDrives[index].cLetter; + pszDevName[count] = pMngr->pDrives[index].pszDevName; + count++; + } + } + + LeaveCriticalSection(&pMngr->csLock); + + while(count--) + { + HANDLE hDevice = CreateFileW(pszDevName[count], GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); + + if (INVALID_HANDLE_VALUE != hDevice) + { + BYTE sc, asc, ascq; + BOOL bReady, bReportChanges, bNeedRecheck; + DWORD ticks; + + bReportChanges = FALSE; + bNeedRecheck = FALSE; + + if(!SPTI_TestUnitReady(hDevice, &sc, &asc, &ascq, 2)) + { + bReady = FALSE; + } + else bReady = (0x00 == sc || (0x02 == sc && 0x3A == asc)); + + CloseHandle(hDevice); + + EnterCriticalSection(&pMngr->csLock); + for (index =0; index < pMngr->nCount; index++) + { + if (pMngr->pDrives[index].cLetter == letters[count]) + { + ticks = GetTickCount(); + if (pMngr->pDrives[index].bMediumInserted && + (ticks - pMngr->pDrives[index].mediumInfo.msLastPolled) > POLLMEDIUMVALIDATE_INTERVAL) bNeedRecheck = TRUE; + pMngr->pDrives[index].mediumInfo.msLastPolled = ticks; + + if (bReady && ((0x00 == sc) != pMngr->pDrives[index].bMediumInserted)) bReportChanges = TRUE; + break; + } + } + LeaveCriticalSection(&pMngr->csLock); + + if (bReportChanges) + { + if (0 == sc) Medium_Add(letters[count], (DWORD)-1); + else Medium_Remove(letters[count]); + } + else if (bNeedRecheck) + { + QueueInfoAPC(letters[count], APC_IsMediumChanged, (DWORD_PTR)letters[count]); + } + + } + } +} + + +static LRESULT WINAPI ListenerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_DEVICECHANGE: + Listener_OnDeviceChange(hwnd, (UINT)wParam, (DWORD_PTR)lParam); + break; + } + return DefWindowProcW(hwnd, uMsg, wParam, lParam); +} + +static void CALLBACK APC_CheckDrives(ULONG_PTR param) +{ + INT index, result, count; + DWORD unitmask, dwOutput; + STORAGE_DEVICE_NUMBER sdn; + DEVICEINFO *pDevInfo; + BYTE buffer[4096] = {0}; + + if (!pMngr) return; + + unitmask = (DWORD)param; + count = 0; + for (int i = 0; i < 26; i++) {if (0x1 & (unitmask >> i)) count++;} + if (!count) return; + + pDevInfo = (DEVICEINFO*)calloc(count, sizeof(DEVICEINFO)); + if (!pDevInfo) return; + + index = 0; + for (int i = 0; i < 26; i++) + { + if (0x1 & unitmask) + { + pDevInfo[index].cLetter = (CHAR)(('A' + i)); + index++; + if (index == count) break; + } + unitmask = unitmask >> 1; + } + + GetDeviceNames(pDevInfo, count); + + for (int i = 0; i < count; i++) + { + HANDLE hDevice = CreateFileW(pDevInfo[i].pszDevName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); + + if (INVALID_HANDLE_VALUE != hDevice) + { + ZeroMemory(&sdn, sizeof(STORAGE_DEVICE_NUMBER)); + result = DeviceIoControl(hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(STORAGE_DEVICE_NUMBER), &dwOutput, NULL); + pDevInfo->deviceNumber = (result) ? sdn.DeviceNumber : -1; + + ZeroMemory(&buffer, sizeof(buffer)/sizeof(BYTE)); + result = DeviceIoControl(hDevice, IOCTL_STORAGE_GET_MEDIA_TYPES_EX, NULL, 0, buffer, sizeof(buffer)/sizeof(BYTE), &dwOutput, NULL); + if (result && buffer && (FILE_DEVICE_DVD & ((GET_MEDIA_TYPES*)buffer)->DeviceType)) pDevInfo[i].dwType = DRIVE_TYPE_DVD; + else pDevInfo[i].dwType = DRIVE_TYPE_CD; + + CloseHandle(hDevice); + } + } + + GetDeviceCaps(pDevInfo, count); + + EnterCriticalSection(&pMngr->csLock); + + for (int i = 0; i < count; i++) + { + pDevInfo[i].opCode = 0; + for (index =0; index < pMngr->nCount; index++) + { + if (pMngr->pDrives[index].cLetter == pDevInfo[i].cLetter) + { + if (-1 == pMngr->pDrives[index].deviceNumber || pMngr->pDrives[index].deviceNumber != pDevInfo[i].deviceNumber) + pDevInfo[i].opCode = 1; + break; + } + } + if (pMngr->nCount == index) pDevInfo[i].opCode = 2; + } + LeaveCriticalSection(&pMngr->csLock); + + for (int i = 0; i < count; i++) + { + if (pDevInfo[i].opCode) Drive_Add(&pDevInfo[i]); + } + + if (pDevInfo) + { + for (int i = 0; i<count; i++) + { + if (pDevInfo[i].pszDevName) free(pDevInfo[i].pszDevName); + } + free(pDevInfo); + } +} + +static void CALLBACK APC_IsMediumChanged(ULONG_PTR param) +{ + INT opCode; + DWORD serial; + + wchar_t devname[4] = L"X:\\"; + + if (!pMngr) return; + + opCode = 0; + devname[0] = (char)(0xFF & param); + if (devname[0]) + { + BOOL result; + + serial = 0; + result = GetVolumeInformationW(devname, NULL, 0, &serial, NULL, NULL, NULL, 0); + if (!result) serial = 0; // perhaps this is empty recordable disc + + EnterCriticalSection(&pMngr->csLock); + + for (INT index =0; index < pMngr->nCount; index++) + { + if (pMngr->pDrives[index].cLetter == (char)param ) + { + pMngr->pDrives[index].mediumInfo.msLastPolled = GetTickCount(); + if (!pMngr->pDrives[index].bMediumInserted && result) opCode = 0x02; + else if (pMngr->pDrives[index].mediumInfo.serialNumber != serial) + { + if (-1 == pMngr->pDrives[index].mediumInfo.serialNumber) pMngr->pDrives[index].mediumInfo.serialNumber = serial; + else opCode = 0x03; + } + break; + } + } + LeaveCriticalSection(&pMngr->csLock); + + if (0x01 & opCode) Medium_Remove((char)param); + if (0x02 & opCode) Medium_Add((char)param, serial); + } +} + +static void CALLBACK APC_AsyncOp_Complete(ULONG_PTR param) +{ + DM_NOTIFY_PARAM *phdr = (DM_NOTIFY_PARAM*)param; + if (phdr->hReserved) + { + CloseHandle(phdr->hReserved); + phdr->hReserved = NULL; + } + + if (phdr->callback) + { + if (phdr->uMsg) + { + if (IsWindow((HWND)phdr->callback)) SendMessageW((HWND)phdr->callback, phdr->uMsg, (WPARAM)DMW_OPCOMPLETED, (LPARAM)phdr); + } + else ((DMNPROC)phdr->callback)(DMW_OPCOMPLETED, (INT_PTR)param); + } + + if (phdr->fnFree) + { + phdr->fnFree(phdr); + } +} + +static void AsycOp_Complete(DM_NOTIFY_PARAM *param) +{ + if (param) QueueUserAPC(APC_AsyncOp_Complete, param->hReserved, (ULONG_PTR)param); +} + +static void CALLBACK APC_GetUnitInfo(ULONG_PTR param) +{ + DWORD unit; + DM_UNITINFO_PARAM *puip; + puip = (DM_UNITINFO_PARAM*)param; + + puip->header.opCode = DMOP_UNITINFO; + + unit = CheckLetter(puip->header.cLetter); + + if (!unit || (!PrimoSDKHelper_IsInitialized() && !PrimoSDKHelper_Initialize())) puip->header.result = PRIMOSDK_CMDSEQUENCE; + else + { + DWORD ready = 0; + CHAR buffer[512] = {0}; + + puip->header.result = PrimoSDKHelper_UnitInfo(&unit, &puip->dwType, + ((DMF_DESCRIPTION & puip->header.fFlags) || (DMF_FIRMWARE & puip->header.fFlags)) ? (BYTE*)buffer: NULL, + (DMF_READY & puip->header.fFlags) ? &ready : NULL); + + if (PRIMOSDK_OK == puip->header.result) + { + if (DMF_READY & puip->header.fFlags) puip->bReady = (0 != ready); + + if (DMF_DESCRIPTION & puip->header.fFlags) + { + INT len = lstrlenA(buffer); + if (len > 5) len -= 5; + if (!puip->pszDesc || puip->cchDesc < (len + 1)) puip->cchDesc = -(len + 1); + else + { + StringCchCopyNA(puip->pszDesc, puip->cchDesc, buffer, len); + puip->cchDesc = len; + } + } + if (DMF_FIRMWARE & puip->header.fFlags) + { + LPSTR p; + INT len = lstrlenA(buffer); + p = buffer + (len - ((len > 5) ? 4 : 0)); + if (!puip->pszFirmware || puip->cchFirmware < 4) puip->cchFirmware = -4; + else + { + StringCchCopyA(puip->pszFirmware, puip->cchFirmware, p); + puip->cchFirmware = 4; + } + } + } + } + AsycOp_Complete(&puip->header); +} + +static void CALLBACK APC_GetUnitInfo2(ULONG_PTR param) +{ + DWORD unit; + DM_UNITINFO2_PARAM *puip; + + puip = (DM_UNITINFO2_PARAM*)param; + puip->header.opCode = DMOP_UNITINFO2; + unit = CheckLetter(puip->header.cLetter); + + if (!unit || (!PrimoSDKHelper_IsInitialized() && !PrimoSDKHelper_Initialize())) puip->header.result = PRIMOSDK_CMDSEQUENCE; + else + { + BOOL bReady; + DWORD szTypes[32], rfu; + + if (DriveManager_IsUnitReady((char)unit, &bReady) && !bReady) + { + SleepEx(1000, TRUE); + QueueUserAPC(APC_GetUnitInfo2, GetCurrentThread(), param); + return; + } + + puip->header.result = PrimoSDKHelper_UnitInfo2(&unit, szTypes, &puip->dwClassId, &puip->dwBusType, &rfu); + if (PRIMOSDK_OK == puip->header.result) + { + if (DMF_TYPES & puip->header.fFlags) + { + INT len; + for (len = 0; szTypes[len] != 0xFFFFFFFF; len++); + + if (!puip->pdwTypes || puip->nTypes < len) puip->nTypes = -len; + else + { + puip->nTypes = len; + if (len) CopyMemory(puip->pdwTypes, szTypes, sizeof(DWORD)*len); + } + } + } + } + AsycOp_Complete(&puip->header); +} +static void CALLBACK APC_GetDiscInfoEx(ULONG_PTR param) +{ + DWORD unit; + DM_DISCINFOEX_PARAM *pdip; + + pdip = (DM_DISCINFOEX_PARAM*)param; + pdip->header.opCode = DMOP_DISCINFO; + unit = CheckLetter(pdip->header.cLetter); + + if (!unit || (!PrimoSDKHelper_IsInitialized() && !PrimoSDKHelper_Initialize())) pdip->header.result = PRIMOSDK_CMDSEQUENCE; + else + { + BOOL bReady; + DWORD dwFlags, dwErasable; + + if (DriveManager_IsUnitReady((char)unit, &bReady) && !bReady) + { + SleepEx(1000, TRUE); + QueueUserAPC(APC_GetDiscInfoEx, GetCurrentThread(), param); + return; + } + + dwFlags = (DMF_DRIVEMODE_TAO & pdip->header.fFlags); + pdip->header.result = PrimoSDKHelper_DiscInfoEx(&unit, dwFlags, + (DMF_MEDIUMTYPE & pdip->header.fFlags) ? &pdip->dwMediumType : NULL, + (DMF_MEDIUMFORMAT & pdip->header.fFlags) ? &pdip->dwMediumFormat : NULL, + &dwErasable, + (DMF_TRACKS & pdip->header.fFlags) ? &pdip->dwTracks: NULL, + (DMF_USED & pdip->header.fFlags) ? &pdip->dwUsed : NULL, + (DMF_FREE & pdip->header.fFlags) ? &pdip->dwFree : NULL); + + if (PRIMOSDK_OK == pdip->header.result) pdip->bErasable = (0 != dwErasable); + } + + AsycOp_Complete(&pdip->header); +} + +static void CALLBACK APC_GetDiscInfo2(ULONG_PTR param) +{ + DWORD unit; + DM_DISCINFO2_PARAM *pdip; + + pdip = (DM_DISCINFO2_PARAM*)param; + pdip->header.opCode = DMOP_DISCINFO2; + unit = CheckLetter(pdip->header.cLetter); + + if (!unit || (!PrimoSDKHelper_IsInitialized() && !PrimoSDKHelper_Initialize())) pdip->header.result = PRIMOSDK_CMDSEQUENCE; + else + { + DWORD rfu, medium, protectedDVD, flags; + + BOOL bReady; + if (DriveManager_IsUnitReady((char)unit, &bReady) && !bReady) + { + SleepEx(1000, TRUE); + QueueUserAPC(APC_GetDiscInfo2, GetCurrentThread(), param); + return; + } + + pdip->header.result = PrimoSDKHelper_DiscInfo2(&unit, + (DMF_MEDIUM & pdip->header.fFlags) ? &pdip->dwMedium : (DMF_MEDIUMEX & pdip->header.fFlags) ? &medium : NULL, + (DMF_PROTECTEDDVD & pdip->header.fFlags) ? &protectedDVD : NULL, + (DMF_PACKETWRITTEN & pdip->header.fFlags) ? &flags : NULL, + (DMF_MEDIUMEX & pdip->header.fFlags) ? &pdip->dwMediumEx : NULL, + &rfu); + if (PRIMOSDK_OK == pdip->header.result) + { + if (DMF_PROTECTEDDVD & pdip->header.fFlags) pdip->bProtectedDVD = (0 != protectedDVD); + if (DMF_PACKETWRITTEN & pdip->header.fFlags) pdip->bPacketWritten = (0 != (PRIMOSDK_PACKETWRITTEN & protectedDVD)); + } + + } + AsycOp_Complete(&pdip->header); +} + +static void CALLBACK APC_GetTitle(ULONG_PTR param) +{ + CHAR cLetter; + DM_TITLE_PARAM *pdtp; + + pdtp = (DM_TITLE_PARAM*)param; + pdtp->header.opCode = DMOP_TITLE; + cLetter = CheckLetter(pdtp->header.cLetter); + + pdtp->header.result = PRIMOSDK_CMDSEQUENCE; + if (cLetter && pdtp->pszTitle) + { + wchar_t name[] = L"X:\\"; + MCIDEVICEID devId; + MCI_OPEN_PARMS op = {0}; + MCI_GENERIC_PARMS gp = {0}; + MCI_STATUS_PARMS sp = {0}; + + name[0] = cLetter; + + op.lpstrDeviceType = (LPWSTR)MCI_DEVTYPE_CD_AUDIO; + op.lpstrElementName = name; + + if (!mciSendCommandW(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT, (DWORD_PTR)&op)) + { + HRESULT hr; + + devId = op.wDeviceID; + sp.dwItem = MCI_STATUS_MEDIA_PRESENT; + INT present = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (BOOL)sp.dwReturn : 0; + + if (present) + { + INT nTracks; + BOOL bAudio; + wchar_t szVolume[256] = {0}; + // check if we have at least one audio track + sp.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; + nTracks = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (INT)sp.dwReturn : -1; + bAudio = FALSE; + + if (nTracks > 0) + { + sp.dwItem = MCI_CDA_STATUS_TYPE_TRACK; + for (sp.dwTrack = 1; sp.dwTrack <= (UINT)nTracks && !bAudio; sp.dwTrack++) + { + mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR)&sp); + bAudio = (MCI_CDA_TRACK_AUDIO == sp.dwReturn); + } + if (bAudio) WASABI_API_LNGSTRINGW_BUF(IDS_CD_AUDIO, szVolume, sizeof(szVolume)/sizeof(wchar_t)); + else + { + INT result; + wchar_t devname[4] = L"X:\\"; + devname[0] = cLetter; + result = GetVolumeInformationW(devname, szVolume, sizeof(szVolume)/sizeof(wchar_t), NULL, NULL, NULL, NULL, 0); + if (!result) WASABI_API_LNGSTRINGW_BUF(IDS_DISC_DATA, szVolume, sizeof(szVolume)/sizeof(wchar_t)); + } + } + else WASABI_API_LNGSTRINGW_BUF(IDS_DISC_BLANK, szVolume, sizeof(szVolume)/sizeof(wchar_t)); + + hr = StringCchPrintfW(pdtp->pszTitle, pdtp->cchTitle, L"%s (%c:)", szVolume, cLetter); + } + else + { + INT nDriveType, nDriveCap; + DWORD type; + wchar_t szDriveType[32] = {0}, szDriveCap[64] = {0}; + + type = DriveManager_GetDriveType(cLetter); + if ((DRIVE_TYPE_UNKNOWN | DRIVE_CAP_UNKNOWN) == type) type = DRIVE_TYPE_CD; + + nDriveCap = ((DRIVE_CAP_R | DRIVE_CAP_RW) & type) ? IDS_RECORDER_CAP : IDS_DRIVE_CAP; + nDriveType = (IDS_DRIVE_CAP == nDriveCap && (DRIVE_TYPE_DVD & type)) ? IDS_DVD : IDS_CD; + + WASABI_API_LNGSTRINGW_BUF(nDriveType, szDriveType, sizeof(szDriveType)/sizeof(wchar_t)); + WASABI_API_LNGSTRINGW_BUF(nDriveCap, szDriveCap, sizeof(szDriveCap)/sizeof(wchar_t)); + hr = StringCchPrintfW(pdtp->pszTitle, pdtp->cchTitle, L"%s %s (%C:)", szDriveType, szDriveCap, cLetter); + } + pdtp->header.result = hr; + mciSendCommandW(devId, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&gp); + } + } + AsycOp_Complete(&pdtp->header); +} + +static void CALLBACK APC_DriveScan(ULONG_PTR param) +{ + char i; + char root[] = "A:\\"; + DWORD unitmask; + DEVICEINFO di = {0}; + + /// detect drives + unitmask = GetLogicalDrives(); + + di.deviceNumber = -1; + di.dwType = DRIVE_TYPE_CD; + + for (i = 0; i < 26; ++i) + { + if (0x1 & (unitmask >> i)) + { + root[0] = ('A' + i); + if(DRIVE_CDROM != GetDriveTypeA(root)) unitmask &= ~(1 << i); + else + { + di.cLetter = root[0]; + Drive_Add(&di); + } + } + } + APC_CheckDrives((ULONG_PTR)unitmask); +} + +#define MAX_TEST_ATTEMPT 20 + +static void CALLBACK APC_Eject(ULONG_PTR param) +{ + INT nCmd; + CHAR cLetter; + BYTE sc(0), asc(0), ascq(0); + + nCmd = HIWORD(param); + cLetter = CheckLetter((CHAR)param); + + if (cLetter && DM_MODE_READY == DriveManager_GetDriveMode(cLetter)) + { + BOOL bSuccess; + HANDLE hDevice; + + hDevice = CreateFileW(GetDeviceName(cLetter), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); + if (INVALID_HANDLE_VALUE != hDevice) + { + DWORD dwOutput; + LARGE_INTEGER start, finish; + + bSuccess = SPTI_TestUnitReady(hDevice, &sc, &asc, &ascq, 3); + if (!bSuccess && ERROR_SEM_TIMEOUT == GetLastError()) + { + bSuccess = TRUE; + sc = 0xFF; + } + + if (bSuccess && (0 == sc || (0x02 == sc && 0x3A == asc))) + { + INT opCode; + opCode = (DM_EJECT_REMOVE == nCmd || 0x00 == sc || (0x3A == asc && 0x01 == ascq)) ? + IOCTL_STORAGE_EJECT_MEDIA : IOCTL_STORAGE_LOAD_MEDIA; + + QueryPerformanceCounter(&start); + bSuccess = DeviceIoControl(hDevice, opCode, NULL, 0, NULL, 0, &dwOutput, NULL); + QueryPerformanceCounter(&finish); + + if (bSuccess && DM_EJECT_CHANGE == nCmd && 0x00 != sc && 0x00 == ascq) + { + finish.QuadPart -= start.QuadPart; + + if (finish.QuadPart < freq.QuadPart && (finish.QuadPart*100000 / freq.QuadPart) < 200) + { + // test unit redy + INT i; + sc = 0x02; asc = 0x04; ascq = 0x01; + for (i = 0; i < MAX_TEST_ATTEMPT && 0x02 == sc && 0x04 == asc && 0x01 == ascq; i++) + { + Sleep(50); + if (!SPTI_TestUnitReady(hDevice, &sc, &asc, &ascq, 3) && ERROR_SEM_TIMEOUT == GetLastError()) + i = MAX_TEST_ATTEMPT; + } + if (i < MAX_TEST_ATTEMPT && 0x02 == sc && 0x3A ==asc) + { + DeviceIoControl(hDevice, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwOutput, NULL); + } + sc = 0x00; + } + } + } + CloseHandle(hDevice); + } + else bSuccess = FALSE; + + if (!bSuccess) + { // we can try MCI + + } + else if (0x00 != sc && !(0x02 == sc && 0x3A == asc)) + { + SleepEx(200, TRUE); + QueueUserAPC(APC_Eject, GetCurrentThread(), param); + return; + } + } +} + +static void CALLBACK APC_GetMCIInfo(ULONG_PTR param) +{ + CHAR cLetter; + MCI_OPEN_PARMS op = {0}; + DM_MCI_PARAM *pmcip; + + pmcip = (DM_MCI_PARAM*)param; + pmcip->header.opCode = DMOP_MCIINFO; + cLetter = CheckLetter(pmcip->header.cLetter); + + pmcip->header.result = PRIMOSDK_CMDSEQUENCE; + if (cLetter) + { + wchar_t name[] = L"X:\\"; + MCIDEVICEID devId; + MCI_INFO_PARMS ip = {0}; + MCI_GENERIC_PARMS gp = {0}; + MCI_STATUS_PARMS sp = {0}; + + name[0] = cLetter; + + op.lpstrDeviceType = (LPWSTR)MCI_DEVTYPE_CD_AUDIO; + op.lpstrElementName = name; + + if (!mciSendCommandW(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT, (DWORD_PTR)&op)) + { + WCHAR buffer[512] = {0}; + INT nMaxTracks = pmcip->nTracks; + + devId = op.wDeviceID; + + if ((DMF_TRACKCOUNT | DMF_TRACKSINFO) & pmcip->header.fFlags) + { + sp.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; + pmcip->nTracks = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (INT)sp.dwReturn : -1; + } + if (DMF_READY & pmcip->header.fFlags) + { + sp.dwItem = MCI_STATUS_READY; + pmcip->bReady = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (BOOL)sp.dwReturn : 0; + } + if (DMF_MODE & pmcip->header.fFlags) + { + sp.dwItem = MCI_STATUS_MODE; + pmcip->uMode = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (UINT)sp.dwReturn : 0; + } + if (DMF_MEDIUMPRESENT & pmcip->header.fFlags) + { + sp.dwItem = MCI_STATUS_MEDIA_PRESENT; + pmcip->bMediumPresent = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (BOOL)sp.dwReturn : 0; + } + if (DMF_MEDIUMUID & pmcip->header.fFlags) + { + ip.dwRetSize = sizeof(buffer)/sizeof(wchar_t); + ip.lpstrReturn= buffer; + if (!mciSendCommandW(devId, MCI_INFO, MCI_WAIT | MCI_INFO_MEDIA_IDENTITY, (DWORD_PTR)&ip)) + { + INT len; + len = lstrlenW(ip.lpstrReturn); + if (S_OK == StringCchCopyW(pmcip->pszMediumUID, pmcip->cchMediumUID, ip.lpstrReturn)) + { + pmcip->cchMediumUID = len; + } + else pmcip->cchMediumUID = 0 - (len + 1); + } + else pmcip->cchMediumUID = -1; + } + if (DMF_MEDIUMUPC & pmcip->header.fFlags) + { + ip.dwCallback = NULL; + ip.dwRetSize = sizeof(buffer)/sizeof(wchar_t); + ip.lpstrReturn = buffer; + if (!mciSendCommandW(devId, MCI_INFO, MCI_WAIT | MCI_INFO_MEDIA_UPC, (DWORD_PTR)&ip)) + { + INT len; + len = lstrlenW(ip.lpstrReturn); + if (S_OK == StringCchCopyW(pmcip->pszMediumUPC, pmcip->cchMediumUPC, ip.lpstrReturn)) + { + pmcip->cchMediumUPC = len; + } + else pmcip->cchMediumUPC = 0 - (len + 1); + } + else pmcip->cchMediumUPC = -1; + } + + if (DMF_TRACKSINFO & pmcip->header.fFlags) + { + MCI_SET_PARMS setp; + + if (nMaxTracks < pmcip->nTracks) pmcip->nTracks = (0 - pmcip->nTracks); + else + { + INT prevPos(0), length(0); + setp.dwTimeFormat = MCI_FORMAT_MILLISECONDS; + mciSendCommandW(devId, MCI_SET, MCI_WAIT | MCI_SET_TIME_FORMAT, (DWORD_PTR)&setp); + + for (int i = pmcip->nTracks; i > 0; i--) + { + sp.dwItem = MCI_CDA_STATUS_TYPE_TRACK; + sp.dwTrack = i; + mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR)&sp); + BOOL bAudio = (MCI_CDA_TRACK_AUDIO == sp.dwReturn); + + sp.dwItem = MCI_STATUS_POSITION; + sp.dwTrack = i; + mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR)&sp); + + if (i != pmcip->nTracks) length = prevPos - (INT)sp.dwReturn; + prevPos = (INT)sp.dwReturn; + + if (i == pmcip->nTracks) + { + sp.dwItem = MCI_STATUS_LENGTH; + sp.dwTrack = i; + mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR)&sp); + length = (INT)sp.dwReturn; + } + + pmcip->pTracks[i- 1] = (0x7FFFFFF & length) | ((bAudio) ? 0x80000000 : 0); + } + + setp.dwTimeFormat = MCI_FORMAT_TMSF; + mciSendCommandW(devId, MCI_SET, MCI_WAIT | MCI_SET_TIME_FORMAT, (DWORD_PTR)&setp); + } + } + + mciSendCommandW(devId, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&gp); + pmcip->header.result = PRIMOSDK_OK; + } + } + + AsycOp_Complete(&pmcip->header); +} + +static void CALLBACK APC_GetIMAPIInfo(ULONG_PTR param) +{ + CHAR cLetter; + BOOL bReady; + HRESULT hr(S_FALSE); + IDiscMaster *pdm; + IDiscRecorder *pdr; + IEnumDiscRecorders *per; + ULONG nActual; + + wchar_t szDevName[] = L"X:\\"; + wchar_t szTargetName[128] = {0}; + DM_IMAPI_PARAM *pIMAPI; + + pIMAPI = (DM_IMAPI_PARAM*)param; + cLetter = CheckLetter(pIMAPI->header.cLetter); + + if (DriveManager_IsUnitReady(cLetter, &bReady) && !bReady) + { + SleepEx(1000, TRUE); + QueueUserAPC(APC_GetIMAPIInfo, GetCurrentThread(), param); + return; + } + + pIMAPI->header.opCode = DMOP_IMAPIINFO; + + pIMAPI->bRecorder = FALSE; + pIMAPI->header.result = (DWORD)E_INVALIDARG; + + szDevName[0] = cLetter; + if (cLetter && QueryDosDeviceW(szDevName, szTargetName, sizeof(szTargetName)/sizeof(wchar_t))) + { + hr = CoCreateInstance(CLSID_MSDiscMasterObj, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IDiscMaster, (void**)&pdm); + if (SUCCEEDED(hr)) + { + hr = pdm->Open(); + if (SUCCEEDED(hr)) + { + IEnumDiscMasterFormats *pef; + hr = pdm->EnumDiscMasterFormats(&pef); + if (SUCCEEDED(hr)) + { + IID pFormats[2]; + hr = pef->Next(sizeof(pFormats)/sizeof(IID), pFormats, &nActual); + if (SUCCEEDED(hr)) + { + while(nActual--) { if (IID_IRedbookDiscMaster == pFormats[nActual]) break; } + if (nActual != ((ULONG)-1)) + { + IRedbookDiscMaster *pdf; + hr = pdm->SetActiveDiscMasterFormat(IID_IRedbookDiscMaster, (void**)&pdf); + if (SUCCEEDED(hr)) + { + pdf->Release(); + hr = pdm->EnumDiscRecorders(&per); + if (SUCCEEDED(hr)) + { + while (S_OK== per->Next(1, &pdr, &nActual) && nActual > 0) + { + BSTR bstrPath; + hr = pdr->GetPath(&bstrPath); + if (SUCCEEDED(hr)) + { + if (0 == lstrcmp(szTargetName, bstrPath)) + { + pIMAPI->bRecorder = TRUE; + if ((DMF_BASEPNPID & pIMAPI->header.fFlags) && FAILED(pdr->GetBasePnPID(&pIMAPI->bstrBasePnPID))) pIMAPI->bstrBasePnPID = NULL; + if ((DMF_DISPLAYNAMES & pIMAPI->header.fFlags) && FAILED(pdr->GetDisplayNames(&pIMAPI->bstrVendorID, &pIMAPI->bstrProductID, &pIMAPI->bstrRevision))) + { + pIMAPI->bstrVendorID = NULL; + pIMAPI->bstrProductID = NULL; + pIMAPI->bstrRevision = NULL; + } + if (DMF_PATH & pIMAPI->header.fFlags) + { + pIMAPI->bstrPath = bstrPath; + bstrPath = NULL; + } + if ((DMF_DRIVESTATE & pIMAPI->header.fFlags) && FAILED(pdr->GetRecorderState(&pIMAPI->ulDriveState))) pIMAPI->ulDriveState = (ULONG)-1; + if ((DMF_DRIVETYPE & pIMAPI->header.fFlags) && FAILED(pdr->GetRecorderType(&pIMAPI->fDriveType))) pIMAPI->fDriveType = 0; + if ((DMF_QUERYMEDIATYPE | DMF_QUERYMEDIAINFO) & pIMAPI->header.fFlags) + { + BOOL bTypeOk(FALSE), bInfoOk(FALSE); + if (SUCCEEDED(pdr->OpenExclusive())) + { + if (0 == (DMF_QUERYMEDIATYPE & pIMAPI->header.fFlags) || + SUCCEEDED(pdr->QueryMediaType(&pIMAPI->fMediaType, &pIMAPI->fMediaFlags))) bTypeOk = TRUE; + if (0 == (DMF_QUERYMEDIAINFO & pIMAPI->header.fFlags) || + SUCCEEDED(pdr->QueryMediaInfo(&pIMAPI->bSessions, &pIMAPI->bLastTrack, &pIMAPI->ulStartAddress, + &pIMAPI->ulNextWritable, &pIMAPI->ulFreeBlocks))) bInfoOk = TRUE; + pdr->Close(); + } + + + if (!bTypeOk) + { + pIMAPI->fMediaType = -1; + pIMAPI->fMediaFlags = -1; + } + if (!bInfoOk) + { + pIMAPI->bLastTrack = 0; + pIMAPI->bSessions = 0; + pIMAPI->ulFreeBlocks = 0; + pIMAPI->ulNextWritable = 0; + pIMAPI->ulStartAddress = 0; + } + + + } + break; + } + if (bstrPath) SysFreeString(bstrPath); + } + pdr->Release(); + } + per->Release(); + } + } + } + } + pef->Release(); + } + pdm->Close(); + } + pdm->Release(); + } + } + pIMAPI->header.result = hr; + AsycOp_Complete(&pIMAPI->header); +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/drivemngr.h b/Src/Plugins/Library/ml_disc/drivemngr.h new file mode 100644 index 00000000..c5e9c2e9 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/drivemngr.h @@ -0,0 +1,239 @@ +#ifndef NULLSOFT_MLDISC_DRIVEMANAGER_HEADER +#define NULLSOFT_MLDISC_DRIVEMANAGER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> +//#include "../primo/obj_primo.h" + +// drive types + +#define DRIVE_TYPE_UNKNOWN 0x00000000 +#define DRIVE_TYPE_CD 0x00000010 +#define DRIVE_TYPE_DVD 0x00000020 +#define DRIVE_CAP_UNKNOWN 0x80000000 +#define DRIVE_CAP_R 0x00010000 +#define DRIVE_CAP_RW 0x00020000 +#define DRIVE_CDR (DRIVE_TYPE_CD | DRIVE_CAP_R ) +#define DRIVE_CDRW (DRIVE_TYPE_CD | DRIVE_CAP_RW) +#define DRIVE_DVDR (DRIVE_TYPE_DVD | DRIVE_CAP_R) +#define DRIVE_DVDRW (DRIVE_TYPE_DVD | DRIVE_CAP_RW) + +#define DMW_DRIVEADDED 0x0001 // param contains drive letter +#define DMW_DRIVEREMOVED 0x0002 // param contains drive letter +#define DMW_DRIVECHANGED 0x0003 // param contains drive letter +#define DMW_MEDIUMARRIVED 0x0004 // param contains drive letter +#define DMW_MEDIUMREMOVED 0x0005 // param contains drive letter +#define DMW_OPCOMPLETED 0x0006 // one of the async opetations completed + +#define DMW_MODECHANGED 0x0010 // LOWORD(param) = MAKEWORD(cLetter, cMode) + +typedef void* HDRVMNGR; + +typedef struct _DM_NOTIFY_PARAM DM_NOTIFY_PARAM; + +typedef void (CALLBACK *DMNPROC)(WORD/*wCode*/, INT_PTR/*param*/); +typedef void (CALLBACK *DMFREEPROC)(DM_NOTIFY_PARAM *phdr); + + +#define DM_EJECT_REMOVE 0 +#define DM_EJECT_LOAD 1 +#define DM_EJECT_CHANGE 2 + +// valid with DM_UNITINFO_PARAM +#define DMF_DESCRIPTION 0x00000001 +#define DMF_FIRMWARE 0x00000002 +#define DMF_READY 0x00000004 + +// valid with DM_UNITINFO2_PARAM +#define DMF_TYPES 0x00000001 + +// valid with DM_DISCINFOEX_PARAM +#define DMF_DRIVEMODE_DAO 0x00000000 +#define DMF_DRIVEMODE_TAO 0x00010000 +#define DMF_MEDIUMTYPE 0x00000001 +#define DMF_MEDIUMFORMAT 0x00000002 +#define DMF_TRACKS 0x00000004 +#define DMF_USED 0x00000008 +#define DMF_FREE 0x00000010 + +// valid with DM_DISCINFO2_PARAM +#define DMF_MEDIUM 0x00000001 +#define DMF_PROTECTEDDVD 0x00000002 +#define DMF_PACKETWRITTEN 0x00000004 +#define DMF_MEDIUMEX 0x00000008 + +// valid with DM_FANCYTITLE_PARAM +#define DMF_VOLUMELABEL 0x00000001 // volume label +#define DMF_CDTEXT 0x00000002 // if set and medium inserted will try to get info from cdtext +#define DMF_CDDB 0x00000004 // if set and medium inserted will try to get info from gracenote +#define DMF_DRIVEDESCRIPTION 0x00000010 // will use PrimoSDK to get drive info + +// valid with DM_MCI_PARAM +#define DMF_READY 0x00000004 // +#define DMF_MEDIUMPRESENT 0x00000002 // +#define DMF_MODE 0x00000001 // +#define DMF_TRACKCOUNT 0x00000008 // +#define DMF_TRACKSINFO 0x00000010 // +#define DMF_MEDIUMUID 0x00000020 // +#define DMF_MEDIUMUPC 0x00000040 // + +// valid with DM_IMAPI_PARAM +#define DMF_BASEPNPID 0x00000001 +#define DMF_DISPLAYNAMES 0x00000002 +#define DMF_PATH 0x00000004 +#define DMF_DRIVESTATE 0x00000008 +#define DMF_DRIVETYPE 0x00000010 +#define DMF_QUERYMEDIATYPE 0x00000020 +#define DMF_QUERYMEDIAINFO 0x00000040 + + +// Operation Codes +#define DMOP_GENERAL 0x0000 +#define DMOP_UNITINFO 0x0001 +#define DMOP_UNITINFO2 0x0002 +#define DMOP_DISCINFO 0x0003 +#define DMOP_DISCINFO2 0x0004 +#define DMOP_TITLE 0x0005 +#define DMOP_MCIINFO 0x0006 +#define DMOP_IMAPIINFO 0x0007 + +// Drive modes +#define DM_MODE_ERROR ((CHAR)(0 - 1)) + +#define DM_MODE_READY 0x00 +#define DM_MODE_BURNING 0x01 +#define DM_MODE_RIPPING 0x02 +#define DM_MODE_COPYING 0x03 + + +typedef struct _DM_NOTIFY_PARAM +{ + INT_PTR callback; // pointer to the callback. If uMsg != 0 callback is HWND, otherwise it is DMNPROC + UINT uMsg; // specify message code to post notification. if 0 callback points to DMNPROC. + CHAR cLetter; // drive letter. + UINT fFlags; // DMF_XXX + DWORD result; // result code. Set by async func. + WORD opCode; // completed opCode (DMOP_XXX). Set by async func. + DMFREEPROC fnFree; // you can specify function that need to be called to free data + HANDLE hReserved; // reserved; +} DM_NOTIFY_PARAM; + + +typedef struct _DM_UNITINFO_PARAM +{ + DM_NOTIFY_PARAM header; + DWORD dwType; // unit type + BOOL bReady; // unit ready flag + LPSTR pszDesc; // pointer to the buffer with unit description. + INT cchDesc; // [in] length of the decription buffer in chars. [out] number of characters written. If error value is negative and show minimum required buffer + LPSTR pszFirmware; // pointer to the buffer with FirmWare ( firmware version is always 4 chars) + INT cchFirmware; // [in] length of the firmware buffer in chars. [out] number of characters written. If error value is negative and show minimum required buffer +} DM_UNITINFO_PARAM; + +typedef struct _DM_UNITINFO2_PARAM +{ + DM_NOTIFY_PARAM header; + DWORD *pdwTypes; // unit types vector + INT nTypes; // vector length (in DWORDS) + DWORD dwClassId; // class identifier assigned to the unit. + DWORD dwBusType; // type of bus to which the device is connected. +} DM_UNITINFO2_PARAM; + + +typedef struct _DM_DISCINFOEX_PARAM +{ + DM_NOTIFY_PARAM header; + DWORD dwMediumType; // type of the medium. + DWORD dwMediumFormat; // format of the media + BOOL bErasable; // + DWORD dwTracks; // number of tracks in the disc. + DWORD dwUsed; // total number of sectors used on the disc. + DWORD dwFree; // total number of free sectors on the disc. + +} DM_DISCINFOEX_PARAM; + +typedef struct _DM_DISCINFO2_PARAM +{ + DM_NOTIFY_PARAM header; + DWORD dwMedium; // physical type of the media. + BOOL bProtectedDVD; // DVD containing copy-protected content. + BOOL bPacketWritten; // if the media is formatted by packet writing software. + DWORD dwMediumEx; // physical type of the medium. +} DM_DISCINFO2_PARAM; + + +typedef struct _DM_TITLE_PARAM +{ + DM_NOTIFY_PARAM header; + LPWSTR pszTitle; + INT cchTitle; + +} DM_TITLE_PARAM; + +typedef struct _DM_MCI_PARAM +{ + DM_NOTIFY_PARAM header; + BOOL bReady; + BOOL bMediumPresent; + UINT uMode; + DWORD* pTracks; // this contains track info (first bit set to '1' if track is audio, other bits track length + INT nTracks; + LPWSTR pszMediumUID; + INT cchMediumUID; + LPWSTR pszMediumUPC; + INT cchMediumUPC; +} DM_MCI_PARAM; + +// you responsible for freeing all bstrs (use SysFreeString()) +typedef struct _DM_IMAPI_PARAM +{ + DM_NOTIFY_PARAM header; // header result contains HRESULT + BOOL bRecorder; // Set to TRUE if IMAPI fond drive + BSTR bstrBasePnPID; // DMF_BASEPNPID + BSTR bstrVendorID; // DMF_DISPLAYNAMES + BSTR bstrProductID; // DMF_DISPLAYNAMES + BSTR bstrRevision; // DMF_DISPLAYNAMES + BSTR bstrPath; // DMF_PATH + ULONG ulDriveState; // DMF_DRIVESTATE + LONG fDriveType; // DMF_DRIVETYPE + LONG fMediaType; // DMF_QUERYMEDIATYPE + LONG fMediaFlags; // DMF_QUERYMEDIATYPE + BYTE bSessions; // DMF_QUERYMEDIAINFO + BYTE bLastTrack; // DMF_QUERYMEDIAINFO + ULONG ulStartAddress; // DMF_QUERYMEDIAINFO + ULONG ulNextWritable; // DMF_QUERYMEDIAINFO + ULONG ulFreeBlocks; // DMF_QUERYMEDIAINFO + +} DM_IMAPI_PARAM; + +BOOL DriveManager_Initialize(DMNPROC DMNProc, BOOL bSuspended); +BOOL DriveManager_Uninitialize(INT msExitWaitTime); +BOOL DriveManager_Suspend(void); +BOOL DriveManager_Resume(BOOL bUpdate); +INT DriveManager_GetDriveList(CHAR *pLetters, INT cchSize); +BOOL DriveManager_Update(BOOL bAsync); // check all drives and discs +BOOL DriveManager_SetDriveMode(CHAR cLetter, CHAR cMode); +CHAR DriveManager_GetDriveMode(CHAR cLetter); +DWORD DriveManager_GetDriveType(CHAR cLetter); +BOOL DriveManager_Eject(CHAR cLetter, INT nCmd); // nCmd = DM_EJECT_XXX +BOOL DriveManager_IsUnitReady(BOOL *pbReady); +BOOL DriveManager_IsMediumInserted(CHAR cLetter); +// PrimoSDK async calls +BOOL DriveManager_GetUnitInfo(DM_UNITINFO_PARAM *puip); +BOOL DriveManager_GetUnitInfo2(DM_UNITINFO2_PARAM *puip); +BOOL DriveManager_GetDiscInfoEx(DM_DISCINFOEX_PARAM *pdip); +BOOL DriveManager_GetDiscInfo2(DM_DISCINFO2_PARAM *pdip); + +BOOL DriveManager_QueryTitle(DM_TITLE_PARAM *pdtp); + +// MCI async +BOOL DriveManager_GetMCIInfo(DM_MCI_PARAM *pmcip); + +//IMAPI async +BOOL DriveManager_GetIMAPIInfo(DM_IMAPI_PARAM *pIMAPI); + + +#endif //NULLSOFT_MLDISC_DRIVEMANAGER_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/drives.cpp b/Src/Plugins/Library/ml_disc/drives.cpp new file mode 100644 index 00000000..cdc29c27 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/drives.cpp @@ -0,0 +1,243 @@ +#include "main.h" +#include <Windows.h> +#include "resource.h" +#include "drives.h" +#include <strsafe.h> + +// +// UNIT TYPES AND MEDIA TYPES +// +#define PRIMOSDK_CDROM 0x00000201 +#define PRIMOSDK_CDR 0x00000202 +#define PRIMOSDK_CDRW 0x00000203 +#define PRIMOSDK_DVDR 0x00000204 +#define PRIMOSDK_DVDROM 0x00000205 +#define PRIMOSDK_DVDRAM 0x00000206 +#define PRIMOSDK_DVDRW 0x00000207 +#define PRIMOSDK_ROBOTICS 0x00000208 +#define PRIMOSDK_DVDPRW 0x00000209 +#define PRIMOSDK_DVDPR 0x00000210 +#define PRIMOSDK_DDCDROM 0x00000211 +#define PRIMOSDK_DDCDR 0x00000212 +#define PRIMOSDK_DDCDRW 0x00000213 +#define PRIMOSDK_DVDPR9 0x00000214 +#define PRIMOSDK_DVDR9 0x00000215 + +// + +#define PRIMOSDK_OTHER 0x00000220 + +// bus type +#define PRIMOSDK_UNKNOWN 0 +#define PRIMOSDK_ATAPI 1 +#define PRIMOSDK_SCSI 2 +#define PRIMOSDK_1394 3 +#define PRIMOSDK_USB 4 +#define PRIMOSDK_USB2 5 + +const wchar_t *typeText[] = {L"UNKNOWN", L"CD-ROM", L"CD-R", L"CD-RW", L"DVD-ROM", L"DVD-R", L"DVD-RW", L"DVD+R", L"DVD+RW", L"DVD-RAM", L"DDCD", L"DDCD-R", L"DDCD-RW", L"DL DVD+R", L"DL DVD-R"}; +const wchar_t *busText[] = {L"UNKNOWN", L"ATAPI", L"SCSI", L"1394", L"USB", L"USB2"}; + +Drives::Drives(void) +{ +} + +Drives::~Drives(void) +{ + Clear(); +} + +void Drives::AddDrive(wchar_t letter, unsigned int typeCode, wchar_t* description, const wchar_t *extInfo) +{ + OPTICAL_DRIVE drive; + drive.letter = (wchar_t)CharUpperW((wchar_t*)letter); + drive.typeCode = typeCode; + drive.modelInfo = (NULL == description) ? NULL : _wcsdup(description); + drive.busType = 0; + drive.disc = NULL; + if (extInfo) + { // extInfo format: bysType;typeCode1;typeCode2;...;typeCoden + const wchar_t *desc = extInfo; + drive.nTypeList = 0; + + while(desc[0] != 0x00) {desc = CharNextW(desc); if (desc[0] == ';') drive.nTypeList ++;} + if (drive.nTypeList) drive.nTypeList; + + drive.pTypeList = (int*) malloc(sizeof(int) * drive.nTypeList); + int *list = drive.pTypeList; + const wchar_t *start = extInfo; + const wchar_t *end = extInfo; + BOOL cont; + do + { + while(end[0] != ';' && end[0] != 0x00) end = CharNextW(end); + + cont = (end[0] == ';') ; + + if (start == extInfo) + drive.busType = _wtoi(start); + else + { + *list = _wtoi(start); + list++; + } + + if(cont) + { + end = CharNextW(end); + start = end; + } + } + while(cont); + } + else + { + drive.nTypeList = 1; + drive.pTypeList = (int*) malloc(sizeof(int) * drive.nTypeList); + drive.pTypeList[0] = typeCode; + } + + Map<wchar_t, OPTICAL_DRIVE>::MapPair insert_pair(drive.letter, drive); + driveList.insert(insert_pair); +} + +void Drives::Clear(void) +{ + for (c_iter = driveList.begin(); c_iter != driveList.end(); c_iter++) + { + if (c_iter->second.modelInfo) free(c_iter->second.modelInfo); + if (c_iter->second.pTypeList) free(c_iter->second.pTypeList); + if (c_iter->second.disc) delete(c_iter->second.disc); + } + driveList.clear(); +} + +unsigned int Drives::GetCount(void) +{ + return (unsigned int)driveList.size(); +} + +const OPTICAL_DRIVE* Drives::GetFirst(void) +{ + c_iter = driveList.begin(); + return (c_iter == driveList.end()) ? NULL : &c_iter->second; +} + +const OPTICAL_DRIVE* Drives::GetNext(void) +{ + return (++c_iter == driveList.end()) ? NULL : &c_iter->second; +} + +BOOL Drives::IsRecorder(const OPTICAL_DRIVE *drive) +{ + BOOL recorder = FALSE; + switch (drive->typeCode) + { + case PRIMOSDK_CDR: + case PRIMOSDK_CDRW: + case PRIMOSDK_DVDR: + case PRIMOSDK_DVDRW: + case PRIMOSDK_DVDPR: + case PRIMOSDK_DVDPRW: + case PRIMOSDK_DVDRAM: + case PRIMOSDK_DDCDR: + case PRIMOSDK_DDCDRW: + case PRIMOSDK_DVDPR9: + case PRIMOSDK_DVDR9: + recorder = TRUE; + break; + } + return recorder; +} + +const wchar_t* Drives::GetTypeString(int typeCode) +{ + int index = 0; + switch (typeCode) + { + case PRIMOSDK_CDROM: + index = 1; + break; + case PRIMOSDK_CDR: + index = 2; + break; + case PRIMOSDK_CDRW: + index = 3; + break; + case PRIMOSDK_DVDROM: + index = 4; + break; + case PRIMOSDK_DVDR: + index = 5; + break; + case PRIMOSDK_DVDRW: + index = 6; + break; + case PRIMOSDK_DVDPR: + index = 7; + break; + case PRIMOSDK_DVDPRW: + index = 8; + break; + case PRIMOSDK_DVDRAM: + index = 9; + break; + case PRIMOSDK_DDCDROM: + index = 10; + break; + case PRIMOSDK_DDCDR: + index = 11; + break; + case PRIMOSDK_DDCDRW: + index = 12; + break; + case PRIMOSDK_DVDPR9: + index = 13; + break; + case PRIMOSDK_DVDR9: + index = 14; + break; + default: + static wchar_t tmp2[64]; + return WASABI_API_LNGSTRINGW_BUF(plugin.hDllInstance,IDS_UNKNOWN,tmp2,64); + } + return typeText[index]; +} + +const wchar_t* Drives::GetBusString(int busCode) +{ + int index = 0; + switch (busCode) + { + case PRIMOSDK_ATAPI: + index = 1; + break; + case PRIMOSDK_SCSI: + index = 2; + break; + case PRIMOSDK_1394: + index = 3; + break; + case PRIMOSDK_USB: + index = 4; + break; + case PRIMOSDK_USB2: + index = 5; + break; + default: + static wchar_t tmp3[64]; + return WASABI_API_LNGSTRINGW_BUF(plugin.hDllInstance,IDS_UNKNOWN,tmp3,64); + } + return busText[index]; +} + +const wchar_t* Drives::GetFormatedString(const OPTICAL_DRIVE *drv, wchar_t *buffer, size_t size, BOOL useFullName) +{ + StringCchPrintfW(buffer, size, WASABI_API_LNGSTRINGW(plugin.hDllInstance,IDS_X_DRIVE_BRACKET_X), + GetTypeString(drv->typeCode), drv->letter); + if (useFullName && drv->modelInfo) + { + StringCchPrintfW(buffer, size, L"%s - %s", buffer, drv->modelInfo); + } + return buffer; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/drives.h b/Src/Plugins/Library/ml_disc/drives.h new file mode 100644 index 00000000..4984607e --- /dev/null +++ b/Src/Plugins/Library/ml_disc/drives.h @@ -0,0 +1,44 @@ +#ifndef NULLSOFT_DRIVEINFO_HEADER +#define NULLSOFT_DRIVEINFO_HEADER + +#include "../nu/Map.h" +#include ".\discinfo.h" + + +typedef struct +{ + wchar_t letter; + int typeCode; + wchar_t* modelInfo; + int busType; + int *pTypeList; // all supported types + int nTypeList; // number of supported tpyes + DiscInfo *disc; // inserted disc info; +} OPTICAL_DRIVE; + +#define MAX_FORMAT_DRIVE_STRING 512 + +class Drives +{ +public: + Drives(void); + ~Drives(void); + +public: + void AddDrive(wchar_t letter, unsigned int typeCode, wchar_t* description, const wchar_t *extInfo); + void Clear(void); + unsigned int GetCount(void); + const OPTICAL_DRIVE* GetFirst(void); + const OPTICAL_DRIVE* GetNext(void); // if returns NULL - means no more + + static BOOL IsRecorder(const OPTICAL_DRIVE *drive); + + static const wchar_t* GetTypeString(int typeCode); + static const wchar_t* GetBusString(int busCode); + static const wchar_t* GetFormatedString(const OPTICAL_DRIVE *drv, wchar_t *buffer, size_t size, BOOL useFullName = TRUE); +private: + Map<wchar_t, OPTICAL_DRIVE> driveList; + Map<wchar_t, OPTICAL_DRIVE>::const_iterator c_iter; +}; + +#endif //NULLSOFT_DRIVEINFO_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/formatfilename.cpp b/Src/Plugins/Library/ml_disc/formatfilename.cpp new file mode 100644 index 00000000..cca31507 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/formatfilename.cpp @@ -0,0 +1,269 @@ +#include "main.h" +#include "../nu/ns_wc.h" +#include "../winamp/wa_ipc.h" +#include <shlwapi.h> +#include <strsafe.h> + +#define TID_UNKNOWN 0 +#define TID_ARTIST 1 +#define TID_ALBUM 2 +#define TID_TITLE 3 +#define TID_GENRE 4 +#define TID_YEAR 5 +#define TID_TRACKARTIST 6 +#define TID_FILENAME 7 +#define TID_EXTENSION 8 +#define TID_DISC 9 +#define TID_DISCS 10 + +#define TOKEN_ARTIST TEXT("<artist>") +#define TOKEN_ALBUM TEXT("<album>") +#define TOKEN_TITLE TEXT("<title>") +#define TOKEN_GENRE TEXT("<genre>") +#define TOKEN_YEAR TEXT("<year>") +#define TOKEN_TRACKARTIST TEXT("<trackartist>") +#define TOKEN_FILENAME TEXT("<filename>") +#define TOKEN_EXTENSION TEXT("<extension>") +#define TOKEN_DISC TEXT("<disc>") +#define TOKEN_DISCS TEXT("<discs>") + +#define TOKEN_LEN_ARTIST 8 +#define TOKEN_LEN_ALBUM 7 +#define TOKEN_LEN_TITLE 7 +#define TOKEN_LEN_GENRE 7 +#define TOKEN_LEN_YEAR 6 +#define TOKEN_LEN_TRACKARTIST 13 +#define TOKEN_LEN_FILENAME 10 +#define TOKEN_LEN_EXTENSION 11 +#define TOKEN_LEN_DISC 6 +#define TOKEN_LEN_DISCS 7 + +#define STRCOMP_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) + +#define CHECK_TOKEN(token, format) (CSTR_EQUAL == CompareString(STRCOMP_INVARIANT, NORM_IGNORECASE, TOKEN_##token##, TOKEN_LEN_##token##, format, TOKEN_LEN_##token##)) + + +static TCHAR PathValidateChar(TCHAR cVal, BOOL bAllowBackSlash) +{ + switch(cVal) + { + case TEXT('\\'): if (!bAllowBackSlash) return TEXT('-'); + break; + case TEXT('/'): if (!bAllowBackSlash) return TEXT('-'); + return TEXT('\\'); + + case TEXT(':'): return TEXT('-'); + case TEXT('*'): return TEXT('_'); + case TEXT('?'): return TEXT('_'); + case TEXT('\"'): return TEXT('\''); + case TEXT('<'): return TEXT('('); + case TEXT('>'): return TEXT(')'); + case TEXT('|'): return TEXT('_'); + } + return cVal; +} + +void CleanupDirectoryString(LPTSTR pszDirectory) +{ + PathUnquoteSpaces(pszDirectory); + PathRemoveBlanks(pszDirectory); + + LPTSTR pc = pszDirectory; + while (TEXT('\0') != *pc) { if (TEXT('/') == *pc) *pc = TEXT('\\'); pc++; } + + if (pc > pszDirectory) + { + pc--; + while (pszDirectory != pc && + (TEXT('.') == *pc || TEXT(' ') == *pc || TEXT('\\') == *pc)) + { + *pc = TEXT('\0'); + pc--; + } + } +} + +LPWSTR GetExtensionString(LPWSTR pszBuffer, INT cchBufferMax, DWORD fourcc) +{ + char configExt[10] = { '\0', }; + pszBuffer[0] = L'\0'; + convertConfigItem cfi; + cfi.configfile = 0; + cfi.data = configExt; + cfi.format = fourcc; + cfi.item = "extension"; + cfi.len = 10; + SENDWAIPC(plugin.hwndWinampParent, IPC_CONVERT_CONFIG_GET_ITEM, (WPARAM)&cfi); + if ('\0' != *configExt) + { + if (!MultiByteToWideCharSZ(CP_ACP, 0, configExt, -1, pszBuffer, cchBufferMax)) + return NULL; + } + else + { + if (cchBufferMax < 5) return NULL; + pszBuffer[0] = (TCHAR)((fourcc) & 0xff); + pszBuffer[1] = (TCHAR)((fourcc >> 8) & 0xff); + pszBuffer[2] = (TCHAR)((fourcc >> 16) & 0xff); + pszBuffer[3] = TEXT('\0'); + for (LPTSTR p = &pszBuffer[2]; p >= pszBuffer && TEXT(' ') == *p; p--) *p = TEXT('\0'); + } + return pszBuffer; +} + +// if trackno is 0xdeadbeef, or title is 0, they are both ignored +// TODO: use ATF instead +HRESULT FormatFileName(LPTSTR pszTextOut, INT cchTextMax, LPCTSTR pszFormat, + INT nTrackNo, LPCTSTR pszArtist, + LPCTSTR pszAlbum, LPCTSTR pszTitle, + LPCTSTR pszGenre, LPCTSTR pszYear, + LPCTSTR pszTrackArtist, + LPCTSTR pszFileName, LPCTSTR pszDisc) +{ + HRESULT hr = S_OK; + TCHAR szBuffer[MAX_PATH] = {0}; + LPTSTR pszStart = pszTextOut + lstrlen(pszTextOut); + + while (pszFormat && TEXT('\0') != *pszFormat) + { + int whichstr = TID_UNKNOWN; + if (*pszFormat == TEXT('#') && nTrackNo != 0xdeadbeef) + { + int cnt = 0; + while (pszFormat && *pszFormat == TEXT('#')) { pszFormat++; cnt++; } + if (cnt > 8) cnt = 8; + + TCHAR szFormat[32] = {0}; + hr = StringCchPrintf(szFormat, ARRAYSIZE(szFormat), TEXT("%%%02dd"), cnt); + if (S_OK == hr) StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), szFormat, nTrackNo); + if (S_OK == hr) StringCchCat(pszTextOut, cchTextMax, szBuffer); + if (S_OK != hr) return hr; + } + else if (pszArtist && CHECK_TOKEN(ARTIST, pszFormat)) whichstr = TID_ARTIST; + else if (pszAlbum && CHECK_TOKEN(ALBUM, pszFormat)) whichstr = TID_ALBUM; + else if (pszTitle && CHECK_TOKEN(TITLE, pszFormat)) whichstr = TID_TITLE; + else if (pszGenre && CHECK_TOKEN(GENRE, pszFormat)) whichstr = TID_GENRE; + else if (pszYear && CHECK_TOKEN(YEAR, pszFormat)) whichstr = TID_YEAR; + else if (pszTrackArtist && CHECK_TOKEN(TRACKARTIST, pszFormat)) whichstr = TID_TRACKARTIST; + else if (pszFileName && CHECK_TOKEN(FILENAME, pszFormat)) whichstr = TID_FILENAME; + else if (pszFileName && CHECK_TOKEN(EXTENSION, pszFormat)) whichstr = TID_EXTENSION; + else if (pszDisc && CHECK_TOKEN(DISC, pszFormat)) whichstr = TID_DISC; + else if (pszDisc && CHECK_TOKEN(DISCS, pszFormat)) whichstr = TID_DISCS; + else + { + INT l = lstrlen(pszTextOut); + pszTextOut += l; + cchTextMax -= l; + pszTextOut[0] = *pszFormat++; + if (cchTextMax < 2) return STRSAFE_E_INSUFFICIENT_BUFFER; + pszTextOut[0] = PathValidateChar(pszTextOut[0], TRUE); + if (TEXT('\\') == *pszTextOut) + { + // remove end spaces and dots + while (pszTextOut > pszStart && + (TEXT('\\') == *(pszTextOut - 1) || TEXT(' ') == *(pszTextOut - 1) || TEXT('.') == *(pszTextOut - 1))) + { + pszTextOut--; + cchTextMax--; + } + + if (pszTextOut == pszStart) + { + pszTextOut--; + cchTextMax--; + } + else *pszTextOut = TEXT('\\'); + } + pszTextOut++; + cchTextMax--; + *pszTextOut = TEXT('\0'); + if (S_OK != hr) return hr; + } + if (whichstr != TID_UNKNOWN) + { + LPCTSTR pszSrc = NULL; + int islow = IsCharLower(pszFormat[1]) && IsCharLower(pszFormat[2]); + int ishi = IsCharUpper(pszFormat[1]) && IsCharUpper(pszFormat[2]); + switch(whichstr) + { + case TID_ARTIST: pszSrc = pszArtist; pszFormat += TOKEN_LEN_ARTIST; break; + case TID_ALBUM: pszSrc = pszAlbum; pszFormat += TOKEN_LEN_ALBUM; break; + case TID_TITLE: pszSrc = pszTitle; pszFormat += TOKEN_LEN_TITLE; break; + case TID_GENRE: pszSrc = pszGenre; pszFormat += TOKEN_LEN_GENRE; break; + case TID_YEAR: pszSrc = pszYear; pszFormat += TOKEN_LEN_YEAR; break; + case TID_TRACKARTIST: pszSrc = pszTrackArtist; pszFormat += TOKEN_LEN_TRACKARTIST; break; + case TID_DISC: + if (pszDisc && *pszDisc && TEXT('\0') == *pszDisc) pszSrc = L"1"; + else + { + // default to 1 when we've not got a proper value passed to us + int disc = _wtoi(pszDisc); + if(disc <= 0) disc = 1; + StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), L"%d", disc); + pszSrc = szBuffer; + } + pszFormat += TOKEN_LEN_DISC; + break; + case TID_DISCS: + if (pszDisc && *pszDisc && TEXT('\0') == *pszDisc) pszSrc = L"1"; + else + { + LPTSTR pszTemp = wcschr((LPTSTR)pszDisc, L'/'); + if(pszTemp == NULL) pszTemp = wcschr((LPTSTR)pszDisc, L'\\'); + if(pszTemp == NULL) + { + pszTemp = (LPTSTR)pszDisc; + } + else + { + pszTemp = CharNext(pszTemp); + } + int disc = _wtoi(pszTemp); + if(disc <= 0) disc = 1; + StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), L"%d", disc); + pszSrc = szBuffer; + } + pszFormat += TOKEN_LEN_DISCS; + break; + case TID_FILENAME: + pszSrc = PathFindExtension(pszFileName); + if (TEXT('\0') == *pszSrc) pszSrc = pszFileName; + else + { + StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), pszFileName); + PathRemoveExtension(szBuffer); + pszSrc = szBuffer; + } + pszFormat += TOKEN_LEN_FILENAME; + break; + case TID_EXTENSION: + pszSrc = PathFindExtension(pszFileName); pszFormat += TOKEN_LEN_EXTENSION; + while (pszTextOut > pszStart && TEXT('.') == *(pszTextOut - 1)) + { + pszTextOut--; + *pszTextOut = TEXT('\0'); + cchTextMax++; + } + break; + } + + INT l = lstrlen(pszTextOut); + pszTextOut += l; + cchTextMax -= l; + + while (pszSrc && TEXT('\0') != *pszSrc && cchTextMax > 0) + { + pszTextOut[0] = pszSrc[0]; + if (ishi) CharUpperBuffW(pszTextOut, 1); + else if (islow) CharLowerBuffW(pszTextOut, 1); + pszTextOut[0] = PathValidateChar(pszTextOut[0], FALSE); + cchTextMax--; + if (cchTextMax) pszTextOut++; + pszSrc++; + } + pszTextOut[0] = TEXT('\0'); + if (0 == cchTextMax) return STRSAFE_E_INSUFFICIENT_BUFFER; + } + } + return hr; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/helpwnd.cpp b/Src/Plugins/Library/ml_disc/helpwnd.cpp new file mode 100644 index 00000000..3bbce8be --- /dev/null +++ b/Src/Plugins/Library/ml_disc/helpwnd.cpp @@ -0,0 +1,350 @@ +#include "main.h" +#include "./resource.h" +#include "../nu/trace.h" +#include <strsafe.h> + +#define MLHELP_PROP TEXT("MLHELP") + +typedef struct __SIMPLEHELP +{ + LPCWSTR pszTitle; + LPCWSTR pszCaption; + LPCWSTR pszText; + HWND hOwner; + UINT uFlags; +} SIMPLEHELP; + +typedef struct __MLHELP +{ + HWND hOwner; + UINT uFlags; + LONG width; + LONG height; +} MLHELP; + +#define GetHelp(__hwnd) ((MLHELP*)GetProp((__hwnd), MLHELP_PROP)) + +#define CLIENT_MIN_WIDTH 280 +#define CLIENT_MIN_HEIGHT 200 +#define CLIENT_MAX_WIDTH 800 +#define CLIENT_MAX_HEIGHT 600 +#define BORDER_SPACE 10 + +static INT_PTR CALLBACK SimpleHelp_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +HWND MLDisc_ShowHelp(HWND hOwner, LPCWSTR pszWindowTitle, LPCWSTR pszCaption, LPCWSTR pszText, UINT uFlags) +{ + SIMPLEHELP help; + help.pszTitle = pszWindowTitle; + help.pszCaption = pszCaption; + help.pszText = pszText; + help.uFlags = uFlags; + help.hOwner = hOwner; + + if (HF_DOMODAL & uFlags) + { + WASABI_API_DIALOGBOXPARAMW(IDD_SIMPLEHELP, hOwner, SimpleHelp_DialogProc, (LPARAM)&help); + return NULL; + } + + return WASABI_API_CREATEDIALOGPARAMW(IDD_SIMPLEHELP, hOwner, SimpleHelp_DialogProc, (LPARAM)&help); +} + +static BOOL FindPrefferedSizeEx(HDC hdc, LPCTSTR pszText, LPCTSTR pszNewLine, SIZE *pSize) +{ + if (!pSize) return FALSE; + pSize->cx = 0; pSize->cy = 0; + if (!hdc || !pszText || !pszNewLine) return FALSE; + LPCTSTR pszBlock = pszText; + LPCTSTR pszCursor = pszBlock; + INT cchSep = lstrlenW(pszNewLine); + INT matched = 0; + for(;;) + { + if (*pszCursor) + { + if (*pszCursor == pszNewLine[matched]) matched++; + else matched = 0; + pszCursor++; + } + if (matched == cchSep || TEXT('\0') == *pszCursor) + { + SIZE sz; + + INT l = (INT)(size_t)((pszCursor - pszBlock) - matched); + if (l > 0) + { + if (!GetTextExtentPoint32(hdc, pszBlock, l, &sz)) return FALSE; + } + else + { + if (!GetTextExtentPoint32(hdc, TEXT("\n"), 1, &sz)) return FALSE; + sz.cx = 0; + } + + + if (pSize->cx < sz.cx) pSize->cx= sz.cx; + pSize->cy += sz.cy; + + if (TEXT('\0') == *pszCursor) break; + else + { + matched = 0; + pszBlock = pszCursor; + } + } + } + return TRUE; +} + +static BOOL FindPrefferedSize(HWND hwnd, LPCTSTR pszText, LPCTSTR pszNewLine, SIZE *pSize) +{ + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_PARENTCLIP); + if (!hdc) return FALSE; + HFONT hf, hfo; + hf = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L); + if (NULL == hf) hf = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + hfo = (NULL != hf) ? (HFONT)SelectObject(hdc, hf) : NULL; + + BOOL br = FindPrefferedSizeEx(hdc, pszText, pszNewLine, pSize); + + if (hfo) SelectObject(hdc, hfo); + ReleaseDC(hwnd, hdc); + + return br; +} + +static INT_PTR SimpleHlp_OnInitDialog(HWND hdlg, HWND hFocus, LPARAM lParam) +{ + SIMPLEHELP *pHelp = (SIMPLEHELP*)lParam; + SIZE sizeCaption = { 0, 0 }; + SIZE sizeText = { 0, 0 }; + SIZE sizeClient = {0, 0}; + SIZE sizeButton = {0, 0}; + + MLHELP *pmlh = (MLHELP*)calloc(1, sizeof(MLHELP)); + if (pmlh) + { + pmlh->hOwner = pHelp->hOwner; + pmlh->uFlags = pHelp->uFlags; + pmlh->height = 0; + pmlh->width = 0; + } + SetProp(hdlg, MLHELP_PROP, (HANDLE)pmlh); + + HWND hctrl; + if(pHelp) + { + + WCHAR szBuffer[4096] = {0}; + if (pHelp->pszTitle) + { + if (IS_INTRESOURCE(pHelp->pszCaption)) + { + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)pHelp->pszTitle, szBuffer, ARRAYSIZE(szBuffer)); + pHelp->pszTitle = szBuffer; + } + SetWindowText(hdlg, pHelp->pszTitle); + } + + if (pHelp->pszCaption) + { + if (IS_INTRESOURCE(pHelp->pszCaption)) + { + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)pHelp->pszCaption, szBuffer, ARRAYSIZE(szBuffer)); + pHelp->pszCaption = szBuffer; + } + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_LBL_CAPTION))) + { + FindPrefferedSize(hctrl, pHelp->pszCaption, TEXT("\n"), &sizeCaption); + SetWindowText(hctrl, pHelp->pszCaption); + } + } + + if (pHelp->pszText) + { + if (IS_INTRESOURCE(pHelp->pszText)) + { + WCHAR form_szBuffer[4096] = {0}, *fszB = form_szBuffer, *szB = szBuffer; + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)pHelp->pszText, form_szBuffer, ARRAYSIZE(form_szBuffer)); + while(fszB && *fszB){ + if(*fszB == L'\n' && *CharPrevW(form_szBuffer,fszB) != L'\r'){ + *szB = L'\r'; + szB = CharNextW(szB); + } + *szB = *fszB; + szB = CharNextW(szB); + fszB = CharNextW(fszB); + } + *szB = 0; + pHelp->pszText = szBuffer; + } + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_EDT_TEXT))) + { + FindPrefferedSize(hctrl, pHelp->pszText, TEXT("\r\n"), &sizeText); + SetWindowText(hctrl, pHelp->pszText); + } + } + + if (0 == (HF_ALLOWRESIZE & pHelp->uFlags)) + { + SetWindowLongPtrW(hdlg, GWL_EXSTYLE, GetWindowLongPtrW(hdlg, GWL_EXSTYLE) | WS_EX_DLGMODALFRAME); + SetWindowLongPtrW(hdlg, GWL_STYLE, (GetWindowLongPtrW(hdlg, GWL_STYLE) & ~WS_THICKFRAME) | DS_MODALFRAME); + } + } + + if (sizeText.cx > 0) sizeText.cx += GetSystemMetrics(SM_CXVSCROLL); + + sizeClient.cx = ((sizeText.cx > sizeCaption.cx) ? sizeText.cx : sizeCaption.cx) + 8; + if (sizeClient.cx < CLIENT_MIN_WIDTH) sizeClient.cx = CLIENT_MIN_WIDTH; + if (sizeClient.cx > CLIENT_MAX_WIDTH) sizeClient.cx = CLIENT_MAX_WIDTH; + sizeText.cx = sizeClient.cx; + sizeCaption.cx = sizeClient.cx; + sizeClient.cx += BORDER_SPACE * 2; + + if (sizeCaption.cy > 0) sizeCaption.cy += 16; + if (sizeCaption.cy > CLIENT_MAX_HEIGHT/3) sizeCaption.cy = CLIENT_MAX_HEIGHT/3; + + if (sizeText.cy > 0) sizeText.cy += 16; + if (sizeText.cy < (CLIENT_MIN_HEIGHT - sizeCaption.cy)) sizeText.cy = (CLIENT_MIN_HEIGHT - sizeCaption.cy); + if (sizeText.cy > (CLIENT_MAX_HEIGHT - sizeCaption.cy)) sizeText.cy = (CLIENT_MAX_HEIGHT - sizeCaption.cy); + + if (NULL != (hctrl = GetDlgItem(hdlg, IDCANCEL))) + { + RECT rw; + if (GetWindowRect(hctrl, &rw)) { sizeButton.cx = rw.right - rw.left; sizeButton.cy = rw.bottom - rw.top; } + } + + LONG top = BORDER_SPACE; + sizeClient.cy = BORDER_SPACE +sizeCaption.cy + sizeText.cy + 8 + sizeButton.cy + BORDER_SPACE; + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_LBL_CAPTION))) + { + if (0 == sizeCaption.cy) EnableWindow(hctrl, FALSE); + SetWindowPos(hctrl, NULL, BORDER_SPACE, top, sizeCaption.cx, sizeCaption.cy, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER); + top += sizeCaption.cy; + } + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_EDT_TEXT))) + { + if (0 == sizeText.cy) EnableWindow(hctrl, FALSE); + SetWindowPos(hctrl, NULL, BORDER_SPACE, top, sizeText.cx, sizeText.cy, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER); + } + + if (NULL != (hctrl = GetDlgItem(hdlg, IDCANCEL))) + { + SetWindowPos(hctrl, NULL, sizeClient.cx - BORDER_SPACE - sizeButton.cx, sizeClient.cy - BORDER_SPACE - sizeButton.cy, + sizeButton.cx, sizeButton.cy, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER); + } + + RECT rw, rc; + if (GetClientRect(hdlg, &rc) && GetWindowRect(hdlg, &rw)) + { + sizeClient.cx += ((rw.right - rw.left) - (rc.right - rc.left)); + sizeClient.cy += ((rw.bottom - rw.top) - (rc.bottom - rc.top)); + } + + SetRect(&rw, 0, 0, 0, 0); + + if (pHelp->hOwner && GetWindowRect(pHelp->hOwner, &rw)) + { + rw.left += ((rw.right - rw.left) - sizeClient.cx)/2; + rw.top += ((rw.bottom - rw.top) - sizeClient.cy)/2; + } + UINT swpFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | ((HF_DOMODAL & pHelp->uFlags) ? SWP_NOZORDER : 0); + pmlh->width = sizeClient.cx; + pmlh->height = sizeClient.cy; + SetWindowPos(hdlg, HWND_TOP, rw.left, rw.top, sizeClient.cx, sizeClient.cy, swpFlags); + return FALSE; +} + +static void SimpleHelp_OnDestroy(HWND hdlg) +{ + MLHELP *pHelp = GetHelp(hdlg); + RemoveProp(hdlg, MLHELP_PROP); + + if (pHelp && 0 == (HF_DOMODAL & pHelp->uFlags) && pHelp->hOwner && IsWindow(pHelp->hOwner)) + SendMessageW(pHelp->hOwner, WM_PARENTNOTIFY, MAKEWPARAM(WM_DESTROY, 0), (LPARAM)hdlg); + if (pHelp) free(pHelp); +} + +static void SimpleHlp_OnCommand(HWND hdlg, INT ctrlId, INT eventId, HWND hctrl) +{ + MLHELP *pHelp = GetHelp(hdlg); + switch(ctrlId) + { + case IDCANCEL: + case IDOK: + if (!pHelp || (HF_DOMODAL & pHelp->uFlags)) EndDialog(hdlg, ctrlId); + else DestroyWindow(hdlg); + break; + } +} + +/*static void SimpleHlp_OnWindowPosChanging(HWND hdlg, WINDOWPOS *pwp) +{ + MLHELP *pHelp = GetHelp(hdlg); + if (!pHelp) return; + + if (0 == (SWP_NOSIZE & pwp->flags)) + { + if (pwp->cx < CLIENT_MIN_WIDTH) pwp->cx = CLIENT_MIN_WIDTH; + if (pwp->cx > CLIENT_MAX_WIDTH) pwp->cx = CLIENT_MAX_WIDTH; + if (pwp->cy < CLIENT_MIN_HEIGHT) pwp->cy = CLIENT_MIN_HEIGHT; + if (pwp->cy > CLIENT_MAX_HEIGHT) pwp->cy = CLIENT_MAX_HEIGHT; + } +} + +static void SimpleHlp_OnWindowPosChanged(HWND hdlg, WINDOWPOS *pwp) +{ + MLHELP *pHelp = GetHelp(hdlg); + if (!pHelp) return; + if (0 == (SWP_NOSIZE & pwp->flags)) + { + RECT rw; + GetWindowRect(hdlg, &rw); + LONG dx = (rw.right - rw.left) - pHelp->width; + LONG dy = (rw.bottom - rw.top) - pHelp->height; + pHelp->width = rw.right - rw.left; + pHelp->height = rw.bottom - rw.top; + + HDWP hdwp = BeginDeferWindowPos(3); + HWND hctrl; + if (hdwp && 0 != dx && NULL != (hctrl = GetDlgItem(hdlg, IDC_LBL_CAPTION)) && GetWindowRect(hctrl, &rw)) + { + hdwp = DeferWindowPos(hdwp, hctrl, NULL, 0, 0, + (rw.right - rw.left) + dx, (rw.bottom - rw.top), SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOREDRAW); + InvalidateRect(hctrl, NULL, TRUE); + } + if (hdwp && (0 != dx || 0 != dy) && + NULL != (hctrl = GetDlgItem(hdlg, IDC_EDT_TEXT)) && GetWindowRect(hctrl, &rw)) + { + hdwp = DeferWindowPos(hdwp, hctrl, NULL, 0, 0, + (rw.right - rw.left) + dx, (rw.bottom - rw.top) + dy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOREDRAW); + } + if (hdwp && (0 != dx || 0 != dy) && + NULL != (hctrl = GetDlgItem(hdlg, IDCANCEL)) && GetWindowRect(hctrl, &rw)) + { + MapWindowPoints(HWND_DESKTOP, hdlg, (POINT*)&rw, 2); + hdwp = DeferWindowPos(hdwp, hctrl, NULL, rw.left + dx, rw.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOREDRAW); + } + if (hdwp && EndDeferWindowPos(hdwp)) + { + RedrawWindow(hdlg, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_INTERNALPAINT | RDW_ALLCHILDREN | RDW_UPDATENOW | RDW_ERASENOW); + } + } +}*/ + +static INT_PTR CALLBACK SimpleHelp_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return SimpleHlp_OnInitDialog(hdlg, (HWND)wParam, lParam); + case WM_DESTROY: SimpleHelp_OnDestroy(hdlg); break; + case WM_COMMAND: SimpleHlp_OnCommand(hdlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break; + /*case WM_WINDOWPOSCHANGING: SimpleHlp_OnWindowPosChanging(hdlg, (WINDOWPOS*)lParam); return 0; + case WM_WINDOWPOSCHANGED: SimpleHlp_OnWindowPosChanged(hdlg, (WINDOWPOS*)lParam); return 0;*/ + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/infoBox.cpp b/Src/Plugins/Library/ml_disc/infoBox.cpp new file mode 100644 index 00000000..23ea2313 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/infoBox.cpp @@ -0,0 +1,145 @@ +#include "main.h" +#include ".\infoBox.h" + + +MLInfoBox::MLInfoBox(void) +{ + oldWndProc = NULL; + m_hwnd = NULL; + bodyBrush = NULL; + headerBrush = NULL; + headerText[0] = 0; + + SetColors(RGB(0,0,0), RGB(255,255,255), RGB(0,60,0)); + + SetRect(&rcBody, 0,0,0,0); + + drawHeader = TRUE; + SetRect(&rcHeader, 0,0,0,20); // default height + + headerFont = NULL; + +} +MLInfoBox::~MLInfoBox(void) +{ + SetWindowLong(m_hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)oldWndProc); + oldWndProc = NULL; + + if (headerBrush) DeleteObject(headerBrush); + headerBrush = NULL; + + if (bodyBrush) DeleteObject(bodyBrush); + bodyBrush = NULL; + + if (headerFont) DeleteObject(headerFont); + headerFont = NULL; + +} + +void MLInfoBox::SetColors(COLORREF bodyBG, COLORREF headerFG, COLORREF headerBG) +{ + this->bodyBG = bodyBG; + this->headerFG = headerFG; + this->headerBG = headerBG; + + if (headerBrush) DeleteObject(headerBrush); + headerBrush = NULL; + headerBrush = CreateSolidBrush(headerBG); + + if (bodyBrush) DeleteObject(bodyBrush); + bodyBrush = NULL; + bodyBrush = CreateSolidBrush(bodyBG); + +} + +void MLInfoBox::Init(HWND hwnd) +{ + m_hwnd = hwnd; + + HDC hdc = GetDC(hwnd); + long lfHeight; + lfHeight = -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72); + headerFont = CreateFontW(lfHeight, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L"Arial"); + ReleaseDC(hwnd, hdc); + + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONGX86)(LONG_PTR)this); + oldWndProc= (WNDPROC)(LONG_PTR)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)newWndProc); + RECT rc; + GetWindowRect(hwnd, &rc); + SetSize(rc.right - rc.left, rc.bottom - rc.top); +} + +void MLInfoBox::SetSize(int cx, int cy) +{ + int offset = 0; + if (drawHeader) + { + SetRect(&rcHeader, 0,0, cx, rcHeader.bottom); + offset = rcHeader.bottom; + } + SetRect(&rcBody, 0, offset, cx, cy); +} +LRESULT CALLBACK MLInfoBox::newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + MLInfoBox *box = (MLInfoBox*)(LONG_PTR)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch(uMsg) + { + case WM_SIZE: + if (SIZE_MINIMIZED != wParam) + { + box->SetSize(LOWORD(lParam), HIWORD(lParam)); + } + break; + case WM_ERASEBKGND: + { + HDC hdc = GetDC(hwndDlg); + SetTextColor(hdc, box->headerFG); + SetBkColor(hdc, box->headerBG); + RECT txtRect; + SetRect(&txtRect, box->rcHeader.left + 8, box->rcHeader.top + 2, box->rcHeader.right -2, box->rcHeader.bottom -2); + HFONT oldFont = (HFONT)SelectObject(hdc, box->headerFont); + GetWindowTextW(hwndDlg, box->headerText, CAPTION_LENGTH); + DrawTextW(hdc, box->headerText, -1, &txtRect, DT_VCENTER | DT_LEFT | DT_SINGLELINE); + SelectObject(hdc, oldFont); + ReleaseDC(hwndDlg, hdc); + } + return TRUE; + + + break; + case WM_PAINT: + { + PAINTSTRUCT pt; + HDC hdc = BeginPaint(hwndDlg, &pt); + RECT drawRect ; + if(box->drawHeader && IntersectRect(&drawRect, &box->rcHeader, &pt.rcPaint)) + { + FillRect(hdc, &drawRect, box->headerBrush); + + SetTextColor(hdc, box->headerFG); + SetBkColor(hdc, box->headerBG); + SetRect(&drawRect, box->rcHeader.left + 8, box->rcHeader.top + 2, box->rcHeader.right -2, box->rcHeader.bottom -2); + HFONT oldFont = (HFONT)SelectObject(hdc, box->headerFont); + GetWindowTextW(hwndDlg, box->headerText, CAPTION_LENGTH); + DrawTextW(hdc, box->headerText, -1, &drawRect, DT_VCENTER | DT_LEFT | DT_SINGLELINE); + SelectObject(hdc, oldFont); + ValidateRect(hwndDlg, &drawRect); + } + + + if(IntersectRect(&drawRect, &box->rcBody, &pt.rcPaint)) + { + FillRect(hdc, &drawRect, box->bodyBrush); + ValidateRect(hwndDlg, &drawRect); + } + + EndPaint(hwndDlg, &pt); + } + break; + } + + return CallWindowProc(box->oldWndProc, hwndDlg, uMsg, wParam, lParam); +} + +
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/infoBox.h b/Src/Plugins/Library/ml_disc/infoBox.h new file mode 100644 index 00000000..b945aab4 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/infoBox.h @@ -0,0 +1,42 @@ +#ifndef NULLSOFT_ML_INFOBOX_HEADER +#define NULLSOFT_ML_INFOBOX_HEADER + +#include <windows.h> + +#define CAPTION_LENGTH 64 +class MLInfoBox +{ +public: + MLInfoBox(void); + ~MLInfoBox(void); + +public: + + void SetColors(COLORREF bodyBG, COLORREF headerFG, COLORREF headerBG); + void Init(HWND hwnd); + +protected: + static LRESULT CALLBACK newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); + void SetSize(int cx, int cy); + +private: + + HWND m_hwnd; + WNDPROC oldWndProc; + + wchar_t headerText[CAPTION_LENGTH]; + BOOL drawHeader; + + COLORREF headerBG; + COLORREF headerFG; + COLORREF bodyBG; + + HFONT headerFont; + + HBRUSH headerBrush; + HBRUSH bodyBrush; + RECT rcBody; + RECT rcHeader; +}; + +#endif // NULLSOFT_ML_INFOBOX_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/main.cpp b/Src/Plugins/Library/ml_disc/main.cpp new file mode 100644 index 00000000..6f39f2f3 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/main.cpp @@ -0,0 +1,1273 @@ +#include "Main.h" +#include "ReplayGain.h" +#include "../nu/AutoChar.h" +#include "../nu/MediaLibraryInterface.h" +#include "./resource.h" +#include "./settings.h" +#include "./copyfiles.h" +#include "../winamp/wa_ipc.h" +//#include <primosdk.h> +#include <shlwapi.h> +#include <imapi.h> +#include <imapierror.h> +#include "../nu/ns_wc.h" +#include <vector> +#include <strsafe.h> + +#define VERSION_MAJOR 2 +#define VERSION_MINOR 0 + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof(*x)) +#endif + +typedef struct _LISTENER +{ + HWND hwnd; + UINT uMsg; + CHAR cLetter; +} LISTENER; + +typedef struct _NAVITEMENUMPARAM +{ + NAVITEMENUMPROC callback; + LPARAM param; +} NAVITEMENUMPARAM; + +typedef enum _BTNSTATE +{ + BTNSTATE_NORMAL = 0, + BTNSTATE_HILITED = 1, + BTNSTATE_PRESSED = 2, + BTNSTATE_DISABLED = 3, +} BTNSTATE; + +#define ICON_SIZE_CX 14 +#define ICON_SIZE_CY 14 + +#define NAVBUTTON_STATECHECK_DELAY 100 +static int Init(); +static void Quit(); + +HNAVITEM hniMain = NULL; +static LRESULT delay_ml_startup; +static HMLIMGLST hmlilIcons = NULL; +LARGE_INTEGER freq; + +#define NAVITEM_PREFIX L"_ml_disc_" +#define NAVITEM_PREFIX_SIZE (sizeof(NAVITEM_PREFIX)/sizeof(wchar_t)) + +#define NCS_EX_SHOWEJECT 0x0100 + +C_Config *g_config, *g_view_metaconf = NULL; +HMENU g_context_menus; + +prefsDlgRecW myPrefsItemCD = {0}; +INT_PTR imgIndex = 0; +wchar_t randb[64] = {0}; +static wchar_t cdrip[64]; + +static DWORD g_navStyle = NCS_FULLROWSELECT | NCS_SHOWICONS; +static DWORD riphash = 0; + +static std::vector<LPARAM> driveList; + +static LISTENER activeListener = { NULL, 0, }; +static WNDPROC oldWinampWndProc = NULL; + +api_application *WASABI_API_APP = 0; +api_stats *AGAVE_API_STATS = 0; + +// wasabi based services for localisation support +api_language *WASABI_API_LNG = 0; +HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0; + +static UINT uMsgBurnerNotify = 0; +static UINT uMsgRipperNotify = 0; +static UINT uMsgNavStyleUpdate = 0; +static UINT uMsgCopyNotify = 0; + +static void CALLBACK Invoke_OnDriveManagerNotify(WORD wCode, INT_PTR param); +static void Plugin_OnMLVisible(BOOL bVisible); +void ShowHideRipBurnParent(void); + + + +static void DriveParam_RegisterDrive(DRIVE *drive) +{ + LPARAM param; + size_t index; + + param = (LPARAM)drive; + if (NULL == param) + return; + + index = driveList.size(); + while(index--) + { + if(param == driveList[index]) + return; + } + + driveList.push_back(param); +} + +static void DriveParam_UnregisterDrive(DRIVE *drive) +{ + LPARAM param; + size_t index; + + param = (LPARAM)drive; + if (NULL == param) + return; + + index = driveList.size(); + while(index--) + { + if(param == driveList[index]) + { + driveList.erase(driveList.begin() + index); + return; + } + } +} + +static BOOL DriveParam_IsValid(LPARAM param) +{ + if (param > 0x0000FFFF) + { + size_t index = driveList.size(); + while(index--) + { + if(param == driveList[index]) + return TRUE; + } + } + return FALSE; +} + +DRIVE *Plugin_GetDriveFromNavItem(HNAVITEM hItem) +{ + NAVITEM item; + + if (!hItem) return NULL; + + item.cbSize = sizeof(NAVITEM); + item.mask = NIMF_PARAM; + item.hItem = hItem; + + return (MLNavItem_GetInfo(plugin.hwndLibraryParent, &item) && DriveParam_IsValid(item.lParam)) ? + (DRIVE*)item.lParam : NULL; +} + +HNAVITEM Plugin_GetNavItemFromLetter(CHAR cLetter) +{ + NAVCTRLFINDPARAMS fp = {0}; + wchar_t invariant[32] = {0}; + + if (S_OK == StringCchPrintfW(invariant, sizeof(invariant)/sizeof(wchar_t), L"%s%c", NAVITEM_PREFIX, cLetter)) + { + fp.cchLength = -1; + fp.pszName = invariant; + fp.compFlags = NICF_INVARIANT; + + return MLNavCtrl_FindItemByName(plugin.hwndLibraryParent, &fp); + } + return NULL; +} + +static BOOL CALLBACK EnumerateNavItemsCB(HNAVITEM hItem, LPARAM param) +{ + DRIVE *pDrive = Plugin_GetDriveFromNavItem(hItem); + return (pDrive) ? ((NAVITEMENUMPARAM*)param)->callback(hItem, pDrive, ((NAVITEMENUMPARAM*)param)->param) : TRUE; +} + +BOOL Plugin_EnumerateNavItems(NAVITEMENUMPROC callback, LPARAM param) +{ + NAVITEMENUMPARAM pluginenum; + NAVCTRLENUMPARAMS navenum; + if (!callback) return FALSE; + + pluginenum.callback = callback; + pluginenum.param = param; + + navenum.hItemStart = hniMain; + navenum.lParam = (LPARAM)&pluginenum; + navenum.enumProc = EnumerateNavItemsCB; + + return MLNavCtrl_EnumItems(plugin.hwndLibraryParent, &navenum); +} + +void Plugin_RegisterListener(HWND hwnd, UINT uMsg, CHAR cLetter) +{ + activeListener.hwnd = hwnd; + activeListener.uMsg = uMsg; + activeListener.cLetter = cLetter; +} + +void Plugin_UnregisterListener(HWND hwnd) +{ + ZeroMemory(&activeListener, sizeof(LISTENER)); +} + +static BOOL CALLBACK EnumNavItems_OnUIChangeCB(HNAVITEM hItem, DRIVE *pDrive, LPARAM param) +{ + if (pDrive) pDrive->textSize = 0; + return TRUE; +} + +static void UpdatedNavStyles(void) +{ + g_navStyle = MLNavCtrl_GetStyle(plugin.hwndLibraryParent); + if (0 != g_view_metaconf->ReadInt(TEXT("showeject"), 1)) g_navStyle |= NCS_EX_SHOWEJECT; +} + +static BOOL CALLBACK EnumerateNavItemsRemoveCB(HNAVITEM hItem, DRIVE *pDrive, LPARAM param) +{ + if(pDrive) + { + MLNavCtrl_DeleteItem(plugin.hwndLibraryParent,hItem); + Plugin_EnumerateNavItems(EnumerateNavItemsRemoveCB, 0); + } + return TRUE; +} + +static BOOL Plugin_QueryOkToQuit() +{ + CHAR szLetters[24] = {0}; + INT c = DriveManager_GetDriveList(szLetters, ARRAYSIZE(szLetters)); + while(c-- > 0) + { + INT msgId; + if (cdrip_isextracting(szLetters[c])) msgId = IDS_YOU_ARE_CURRENTLY_RIPPING_AUDIO_CD_MUST_CANCEL_TO_CLOSE_WINAMP; + else if (MLDisc_IsDiscCopying(szLetters[c])) msgId = IDS_YOU_ARE_CURRENTLY_COPYING_DATA_CD_MUST_CANCEL_TO_CLOSE_WINAMP; + else msgId = 0; + if (msgId) + { + wchar_t buffer[512] = {0}; + StringCchPrintfW(buffer, 512, WASABI_API_LNGSTRINGW(msgId), szLetters[c]); + MessageBoxW(plugin.hwndWinampParent, buffer, WASABI_API_LNGSTRINGW(IDS_NOTIFICATION), + MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST); + return FALSE; + } + } + return TRUE; +} + +LRESULT CALLBACK WinampWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if(uMsgNavStyleUpdate == uMsg) + { + if(!wParam) + { + UpdatedNavStyles(); + Plugin_EnumerateNavItems(EnumNavItems_OnUIChangeCB, 0); + } + else + { + Plugin_EnumerateNavItems(EnumerateNavItemsRemoveCB, 0); + ShowHideRipBurnParent(); + DriveManager_Uninitialize(0); + DriveManager_Initialize(Invoke_OnDriveManagerNotify, TRUE); + Plugin_OnMLVisible((BOOL)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_IS_VISIBLE, 0)); + } + } + else if (uMsgBurnerNotify == uMsg) // burner broadcast message LOWORD(wParam) = drive letter, lParam = (BOOL)bStarted. if bStarted = TRUE - burning started, otherwise burning finished + { + if (0 == HIWORD(wParam)) + { + DriveManager_SetDriveMode((CHAR)LOWORD(wParam), (0 != lParam) ? DM_MODE_BURNING : DM_MODE_READY); + } + } + else if (uMsgRipperNotify == uMsg) + { + if (HIWORD(wParam)) // another instance of winamp quering + { + if (LOWORD(wParam) && cdrip_isextracting((CHAR)LOWORD(wParam))) SendNotifyMessage((HWND)lParam, uMsgRipperNotify, LOWORD(wParam), (LPARAM)TRUE); + else + { + CHAR cLetter; + cLetter = (CHAR)cdrip_isextracting(-1); + if (cLetter) SendNotifyMessage((HWND)lParam, uMsgRipperNotify, cLetter, (LPARAM)TRUE); + } + } + else + { + DriveManager_SetDriveMode((CHAR)LOWORD(wParam), (0 != lParam) ? DM_MODE_RIPPING : DM_MODE_READY); + } + } + else if (uMsgCopyNotify == uMsg) + { + if (HIWORD(wParam)) + { + if (LOWORD(wParam) && MLDisc_IsDiscCopying((CHAR)LOWORD(wParam))) SendNotifyMessage((HWND)lParam, uMsgCopyNotify, LOWORD(wParam), (LPARAM)TRUE); + else + { + CHAR szLetters[24] = {0}; + INT c = DriveManager_GetDriveList(szLetters, ARRAYSIZE(szLetters)); + while(c-- > 0) + { + if (MLDisc_IsDiscCopying(szLetters[c])) + SendNotifyMessage((HWND)lParam, uMsgCopyNotify, szLetters[c], (LPARAM)TRUE); + } + } + } + else + { + DriveManager_SetDriveMode((CHAR)LOWORD(wParam), (0 != lParam) ? DM_MODE_COPYING : DM_MODE_READY); + } + } + else if (WM_WA_IPC == uMsg) + { + switch(lParam) + { + case IPC_SKIN_CHANGED: + case IPC_CB_RESETFONT: + UpdatedNavStyles(); + Plugin_EnumerateNavItems(EnumNavItems_OnUIChangeCB, 0); + break; + case IPC_FILE_TAG_MAY_HAVE_UPDATED: + case IPC_FILE_TAG_MAY_HAVE_UPDATEDW: + if (activeListener.hwnd) SendMessageW(activeListener.hwnd, activeListener.uMsg, (WPARAM)lParam, (LPARAM)wParam); + break; + } + if(lParam == delay_ml_startup) + { + if(!wParam) + { + PostMessage(plugin.hwndWinampParent, WM_WA_IPC, 1, delay_ml_startup); + } + else if(wParam == 1) + { + // TODO: benski> temp-hack fix for now -- if (SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_IS_VISIBLE, 0)) + { + DriveManager_Initialize(Invoke_OnDriveManagerNotify, TRUE); + MLDisc_InitializeCopyData(); + + DriveManager_Resume(TRUE); + SendNotifyMessage(HWND_BROADCAST, uMsgBurnerNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent); + SendNotifyMessage(HWND_BROADCAST, uMsgRipperNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent); + SendNotifyMessage(HWND_BROADCAST, uMsgCopyNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent); + } + } + } + } + return (oldWinampWndProc) ? CallWindowProcW(oldWinampWndProc, hwnd, uMsg, wParam, lParam) : DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +static DM_UNITINFO2_PARAM unitinfo; +static char szDesc[1024]; +static DWORD szTypes[64]; + +static void CALLBACK FreeParam(DM_NOTIFY_PARAM *phdr) +{ + if (!phdr) return; + switch(phdr->opCode) + { + case DMOP_TITLE: + if (((DM_TITLE_PARAM*)phdr)->pszTitle) free(((DM_TITLE_PARAM*)phdr)->pszTitle); + break; + } + free(phdr); +} +static void RegisterIcons() +{ + MLIMAGELISTCREATE mlilCreate; + MLIMAGESOURCE mlis; + MLIMAGELISTITEM mlilItem; + + if (hmlilIcons) return; + + mlilCreate.cx = ICON_SIZE_CX; + mlilCreate.cy = ICON_SIZE_CY; + mlilCreate.cInitial = 5; + mlilCreate.cGrow = 1; + mlilCreate.cCacheSize = 3; + mlilCreate.flags = MLILC_COLOR24; + + hmlilIcons = MLImageList_Create(plugin.hwndLibraryParent, &mlilCreate); + if (!hmlilIcons) return; + + ZeroMemory(&mlilItem, sizeof(MLIMAGELISTITEM)); + mlilItem.cbSize = sizeof(MLIMAGELISTITEM); + mlilItem.hmlil = hmlilIcons; + mlilItem.filterUID = MLIF_FILTER1_UID; + mlilItem.pmlImgSource = &mlis; + + ZeroMemory(&mlis, sizeof(MLIMAGESOURCE)); + mlis.cbSize = sizeof(MLIMAGESOURCE); + mlis.type = SRC_TYPE_PNG; + mlis.hInst = plugin.hDllInstance; + + mlis.lpszName = MAKEINTRESOURCEW(IDB_NAVITEM_CDROM); + MLImageList_Add(plugin.hwndLibraryParent, &mlilItem); + + mlis.lpszName = MAKEINTRESOURCEW(IDB_EJECT_NORMAL); + MLImageList_Add(plugin.hwndLibraryParent, &mlilItem); + + mlis.lpszName = MAKEINTRESOURCEW(IDB_EJECT_HILITED); + MLImageList_Add(plugin.hwndLibraryParent, &mlilItem); + + mlis.lpszName = MAKEINTRESOURCEW(IDB_EJECT_PRESSED); + MLImageList_Add(plugin.hwndLibraryParent, &mlilItem); + + mlis.lpszName = MAKEINTRESOURCEW(IDB_EJECT_DISABLED); + MLImageList_Add(plugin.hwndLibraryParent, &mlilItem); + +} + + +static BOOL UpdateTitle(CHAR cLetter, LPCWSTR pszTitle) +{ + HNAVITEM hItem; + NAVITEM item; + DRIVE *pDrive; + + hItem = Plugin_GetNavItemFromLetter(cLetter); + if (!hItem) return FALSE; + + pDrive = Plugin_GetDriveFromNavItem(hItem); + if (!pDrive) return FALSE; + + if (S_OK != StringCchCopyW(pDrive->szTitle, sizeof(pDrive->szTitle)/sizeof(wchar_t), (pszTitle) ? pszTitle : L"")) return FALSE; + + pDrive->textSize = 0; + + item.cbSize = sizeof(NAVITEM); + item.mask = NIMF_TEXT; + item.hItem = hItem; + item.pszText = pDrive->szTitle; + + return MLNavItem_SetInfo(plugin.hwndLibraryParent, &item); + +} +static void QueryTitle(CHAR cLetter) +{ + DM_TITLE_PARAM *pdtp; + + pdtp = (DM_TITLE_PARAM*)calloc(4, sizeof(DM_TITLE_PARAM)); + if (pdtp) + { + pdtp->header.callback = (INT_PTR)Invoke_OnDriveManagerNotify; + pdtp->header.cLetter = cLetter; + pdtp->header.uMsg = NULL; + pdtp->header.fnFree = FreeParam; + pdtp->cchTitle = 256; + pdtp->pszTitle = (wchar_t*)calloc(pdtp->cchTitle, sizeof(wchar_t)); + + DriveManager_QueryTitle(pdtp); + } +} +static void Drive_OnAdded(CHAR cLetter) +{ + wchar_t szInvariant[32] = {0}; + + DRIVE *pDrive; + NAVINSERTSTRUCT nis = {0}; + wchar_t szDriveType[32] = {0}, szDriveCap[64] = {0}; + + pDrive = (DRIVE*)calloc(1, sizeof(DRIVE)); + if (!pDrive) return; + + StringCchPrintfW(szInvariant, sizeof(szInvariant)/sizeof(wchar_t), L"%s%c", NAVITEM_PREFIX, cLetter); + + pDrive->cLetter = cLetter; + pDrive->cMode = DriveManager_GetDriveMode(cLetter); + + WASABI_API_LNGSTRINGW_BUF(IDS_CD, szDriveType, sizeof(szDriveType)/sizeof(wchar_t)); + WASABI_API_LNGSTRINGW_BUF(IDS_DRIVE_CAP, szDriveCap, sizeof(szDriveCap)/sizeof(wchar_t)); + StringCchPrintfW(pDrive->szTitle, sizeof(pDrive->szTitle)/sizeof(wchar_t), L"%s %s (%C:)", szDriveType, szDriveCap, (WCHAR)cLetter); + + if (NULL == hmlilIcons) RegisterIcons(); + + ZeroMemory(&nis, sizeof(NAVINSERTSTRUCT)); + nis.hParent = hniMain; + nis.item.cbSize = sizeof(NAVITEM); + nis.item.pszText = pDrive->szTitle; + nis.item.pszInvariant = szInvariant; + nis.item.mask = NIMF_TEXT | NIMF_TEXTINVARIANT | NIMF_PARAM | NIMF_STYLE; + nis.item.style = NIS_CUSTOMDRAW | NIS_WANTSETCURSOR | NIS_WANTHITTEST; + nis.item.styleMask = nis.item.style; + nis.item.lParam = (LPARAM)pDrive; + + if (NULL != MLNavCtrl_InsertItem(plugin.hwndLibraryParent, &nis)) + { + DriveParam_RegisterDrive(pDrive); + } +} + +static void Drive_OnChanged(CHAR cLetter) +{ + QueryTitle(cLetter); +} + +static void Drive_OnRemoved(CHAR cLetter) +{ + HNAVITEM hItem; + hItem = Plugin_GetNavItemFromLetter(cLetter); + if (hItem) MLNavCtrl_DeleteItem(plugin.hwndLibraryParent, hItem); + if (riphash && (0xFF & (riphash >> 24)) == (UCHAR)cLetter) riphash = 0; +} + +static void Drive_OnModeChanged(CHAR cLetter, CHAR cMode) +{ + HNAVITEM hItem; + DRIVE *pDrive; + + hItem = Plugin_GetNavItemFromLetter(cLetter); + if (!hItem) return; + + pDrive = Plugin_GetDriveFromNavItem(hItem); + if (pDrive) + { + NAVITEMINAVLIDATE inv; + + pDrive->cMode = cMode; + + inv.fErase = FALSE; + inv.hItem = hItem; + inv.prc = NULL; + MLNavItem_Invalidate(plugin.hwndLibraryParent, &inv); + } +} + +static void Medium_OnAdded(CHAR cLetter) +{ + if (riphash && (0xFF & (riphash >> 24)) == (UCHAR)cLetter) riphash = 0; + QueryTitle(cLetter); +} + +static void Medium_OnRemoved(CHAR cLetter) +{ + if (riphash && (0xFF & (riphash >> 24)) == (UCHAR)cLetter) riphash = 0; + QueryTitle(cLetter); +} + +static void OnDriveMangerOpCompleted(DM_NOTIFY_PARAM *phdr) +{ + switch(phdr->opCode) + { + case DMOP_TITLE: + if (S_OK == phdr->result) UpdateTitle(phdr->cLetter, ((DM_TITLE_PARAM*)phdr)->pszTitle); + break; + } +} + +static void CALLBACK OnDriveManagerNotify(ULONG_PTR param) +{ + WORD code; + CHAR cLetter; + + code = LOWORD(param); + cLetter = (CHAR)(0xFF & HIWORD(param)); + + switch(code) + { + case DMW_DRIVEADDED: Drive_OnAdded(cLetter); break; + case DMW_DRIVEREMOVED: Drive_OnRemoved(cLetter); break; + case DMW_DRIVECHANGED: Drive_OnChanged(cLetter); break; + case DMW_MEDIUMARRIVED: Medium_OnAdded(cLetter); break; + case DMW_MEDIUMREMOVED: Medium_OnRemoved(cLetter); break; + case DMW_MODECHANGED: Drive_OnModeChanged(cLetter, ((CHAR)(HIWORD(param)>>8))); break; + + } + if (activeListener.hwnd && (0 == activeListener.cLetter || cLetter == activeListener.cLetter)) + PostMessageW(activeListener.hwnd, activeListener.uMsg, (WPARAM)code, (LPARAM)HIWORD(param)); +} + +static void CALLBACK Invoke_OnDriveManagerNotify(WORD wCode, INT_PTR param) +{ + switch(wCode) + { + case DMW_DRIVEADDED: + case DMW_DRIVEREMOVED: + case DMW_DRIVECHANGED: + case DMW_MEDIUMARRIVED: + case DMW_MEDIUMREMOVED: + case DMW_MODECHANGED: + if (GetCurrentThreadId() != GetWindowThreadProcessId(plugin.hwndLibraryParent, NULL)) + { + HANDLE htWA = (WASABI_API_APP) ? WASABI_API_APP->main_getMainThreadHandle() : NULL; + if (htWA) + { + QueueUserAPC(OnDriveManagerNotify, htWA, MAKELONG(wCode, (WORD)(param))); + CloseHandle(htWA); + } + } + else OnDriveManagerNotify(MAKELONG(wCode, (WORD)(param))); + break; + case DMW_OPCOMPLETED: OnDriveMangerOpCompleted((DM_NOTIFY_PARAM*)param); break; + } +} + +void ShowHideRipBurnParent(void) +{ + BOOL bVal; + if (S_OK == Settings_GetBool(C_GLOBAL, GF_SHOWPARENT, &bVal) && bVal) + { + if(!hniMain) + { + NAVINSERTSTRUCT nis; + ZeroMemory(&nis, sizeof(NAVITEM)); + nis.item.cbSize = sizeof(NAVITEM); + nis.item.pszText = WASABI_API_LNGSTRINGW_BUF(IDS_RIP_AND_BURN, randb,64); + nis.item.pszInvariant = NAVITEM_PREFIX L"main"; + nis.item.mask = NIMF_TEXT | NIMF_STYLE | NIMF_TEXTINVARIANT | NIMF_PARAM; + nis.item.style = NIS_HASCHILDREN; + nis.item.styleMask = nis.item.style; + nis.item.lParam = 0L; + hniMain = MLNavCtrl_InsertItem(plugin.hwndLibraryParent, &nis); + } + } + else + { + if(hniMain) + { + MLNavCtrl_DeleteItem(plugin.hwndLibraryParent,hniMain); + } + hniMain = NULL; + } +} + +int Init() +{ + QueryPerformanceFrequency(&freq); + + // get the Application service + waServiceFactory *sf = plugin.service->service_getServiceByGuid(applicationApiServiceGuid); + if (sf) WASABI_API_APP = (api_application *)sf->getInterface(); + + // loader so that we can get the localisation service api for use + sf = plugin.service->service_getServiceByGuid(languageApiGUID); + if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface()); + + sf = plugin.service->service_getServiceByGuid(AnonymousStatsGUID); + if (sf) AGAVE_API_STATS = reinterpret_cast<api_stats*>(sf->getInterface()); + + // need to have this initialised before we try to do anything with localisation features + WASABI_API_START_LANG(plugin.hDllInstance,MlDiscLangGUID); + + mediaLibrary.library = plugin.hwndLibraryParent; + mediaLibrary.winamp = plugin.hwndWinampParent; + mediaLibrary.instance = plugin.hDllInstance; + + static wchar_t szDescription[256]; + StringCchPrintf(szDescription, ARRAYSIZE(szDescription), + WASABI_API_LNGSTRINGW(IDS_NULLSOFT_RIP_AND_BURN), VERSION_MAJOR, VERSION_MINOR); + plugin.description = (char*)szDescription; + + // add to Winamp preferences + myPrefsItemCD.dlgID = IDD_PREFSCDRIPFR; + myPrefsItemCD.name = WASABI_API_LNGSTRINGW_BUF(IDS_CD_RIPPING,cdrip,64); + myPrefsItemCD.proc = (void*)CDRipPrefsProc; + myPrefsItemCD.hInst = WASABI_API_LNG_HINST; + myPrefsItemCD.where = 6; // media library + SENDWAIPC(plugin.hwndWinampParent, IPC_ADD_PREFS_DLGW, (WPARAM)&myPrefsItemCD); + + wchar_t szIniFile[MAX_PATH], + *INI_DIR = (wchar_t*)SENDWAIPC(plugin.hwndWinampParent, IPC_GETINIDIRECTORYW, 0); + + PathCombine(szIniFile, INI_DIR, TEXT("Plugins\\gen_ml.ini")); + g_config = new C_Config(szIniFile); + + PathCombine(szIniFile, INI_DIR, TEXT("Plugins\\ml\\cdrom.vmd")); + g_view_metaconf = new C_Config(szIniFile); + + g_context_menus = WASABI_API_LOADMENU(IDR_CONTEXTMENUS); + + oldWinampWndProc = (WNDPROC)(LONG_PTR)SetWindowLongPtrW(plugin.hwndWinampParent, GWLP_WNDPROC, (LONG)(LONG_PTR)WinampWndProc); + + if (!uMsgBurnerNotify) uMsgBurnerNotify = RegisterWindowMessageA("WABURNER_BROADCAST_MSG"); + if (!uMsgRipperNotify) uMsgRipperNotify = RegisterWindowMessageA("WARIPPER_BROADCAST_MSG"); + if (!uMsgCopyNotify) uMsgCopyNotify = RegisterWindowMessageA("WACOPY_BROADCAST_MSG"); + if (!uMsgNavStyleUpdate) uMsgNavStyleUpdate = RegisterWindowMessageW(L"ripburn_nav_update"); + + UpdatedNavStyles(); + ShowHideRipBurnParent(); + + delay_ml_startup = SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"ml_disc_delay", IPC_REGISTER_WINAMP_IPCMESSAGE); + PostMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, delay_ml_startup); + return ML_INIT_SUCCESS; +} + +void Quit() +{ + DriveManager_Uninitialize(4000); // allow to wait for 4 sec. + MLDisc_ReleaseCopyData(); + delete(g_view_metaconf); + g_view_metaconf = 0; + + delete(g_config); + g_config = NULL; + + if (rgThread) + { + QueueUserAPC(QuitThread, rgThread, 0); + WaitForSingleObject(rgThread, INFINITE); + CloseHandle(rgThread); + rgThread = 0; + } + + waServiceFactory *sf = plugin.service->service_getServiceByGuid(AnonymousStatsGUID); + if (sf) sf->releaseInterface(AGAVE_API_STATS); +} + +int getFileInfo(const char *filename, const char *metadata, char *dest, int len) +{ + dest[0] = 0; + extendedFileInfoStruct efis = { filename, metadata, dest, len, }; + return (int)(INT_PTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM) & efis, IPC_GET_EXTENDED_FILE_INFO); //will return 1 if wa2 supports this IPC call +} + +int getFileInfoW(const wchar_t *filename, const wchar_t *metadata, wchar_t *dest, int len) +{ + if (dest && len) + dest[0] = 0; + extendedFileInfoStructW efis = { filename, metadata, dest, len, }; + return (int)(INT_PTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&efis, IPC_GET_EXTENDED_FILE_INFOW); //will return 1 if wa2 supports this IPC call +} + + +void Plugin_ShowRippingPreferences(void) +{ + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&myPrefsItemCD, IPC_OPENPREFSTOPAGE); +} +BOOL Plugin_IsExtractScheduled(CHAR cLetter) +{ + BOOL result; + if (riphash && (0xFF & (riphash >> 24)) == (UCHAR)cLetter) + { + DWORD mediumSN; + char devname[] = "X:\\"; + devname[0] = cLetter; + result = (GetVolumeInformationA(devname, NULL, 0, &mediumSN, NULL, NULL, NULL, 0) && (0x00FFFFFF & riphash) == mediumSN); + riphash = 0; + } + else result = FALSE; + return result; +} + + +static int Root_OnContextMenu(HNAVITEM hItem, HWND hHost, POINTS pts) +{ + HMENU hMenu = GetSubMenu(g_context_menus, 7); + if (!hMenu) return 0; + + POINT pt; + POINTSTOPOINT(pt, pts); + if (-1 == pt.x || -1 == pt.y) + { + NAVITEMGETRECT itemRect; + itemRect.fItem = FALSE; + itemRect.hItem = hItem; + if (MLNavItem_GetRect(plugin.hwndLibraryParent, &itemRect)) + { + MapWindowPoints(hHost, HWND_DESKTOP, (POINT*)&itemRect.rc, 2); + pt.x = itemRect.rc.left + 2; + pt.y = itemRect.rc.top + 2; + } + } + + int r = Menu_TrackPopup(plugin.hwndLibraryParent, hMenu, + TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_NONOTIFY, + pt.x, pt.y, hHost, NULL); + switch (r) + { + case ID_NAVIGATION_PREFERENCES: Plugin_ShowRippingPreferences(); return 1; + case ID_NAVIGATION_HELP: SENDWAIPC(plugin.hwndWinampParent, IPC_OPEN_URL, L"https://help.winamp.com/hc/articles/8111574760468-CD-Ripping-with-Winamp"); return 1; + break; + } + return 0; +} + +static int Plugin_OnContextMenu(HNAVITEM hItem, HWND hHost, POINTS pts, CHAR cLetter) +{ + HMENU hMenu = GetSubMenu(g_context_menus, 2); + if (!hMenu) return 0; + + MENUITEMINFO mii = { sizeof(MENUITEMINFO), }; + mii.fMask = MIIM_STATE; + if (GetMenuItemInfo(hMenu, ID_CDROMMENU_EJECTCD, FALSE, &mii)) + { + mii.fState &= ~(MFS_ENABLED | MFS_DISABLED); + mii.fState |= ((DM_MODE_READY == DriveManager_GetDriveMode(cLetter)) ? MFS_ENABLED : MFS_DISABLED); + SetMenuItemInfo(hMenu, ID_CDROMMENU_EJECTCD, FALSE, &mii); + } + + POINT pt; + POINTSTOPOINT(pt, pts); + if (-1 == pt.x || -1 == pt.y) + { + NAVITEMGETRECT itemRect; + itemRect.fItem = FALSE; + itemRect.hItem = hItem; + if (MLNavItem_GetRect(plugin.hwndLibraryParent, &itemRect)) + { + MapWindowPoints(hHost, HWND_DESKTOP, (POINT*)&itemRect.rc, 2); + pt.x = itemRect.rc.left + 2; + pt.y = itemRect.rc.top + 2; + } + } + + int r = Menu_TrackPopup(plugin.hwndLibraryParent, hMenu, + TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_NONOTIFY, + pt.x, pt.y, hHost, NULL); + switch (r) + { + case ID_CDROMMENU_EXTRACT_CONFIGURE: Plugin_ShowRippingPreferences(); return 1; + case ID_CDROMMENU_EXTRACT_HELP: SENDWAIPC(plugin.hwndWinampParent, IPC_OPEN_URL, L"https://help.winamp.com/hc/articles/8111574760468-CD-Ripping-with-Winamp"); return 1; + case ID_CDROMMENU_PLAYALL: + case ID_CDROMMENU_ENQUEUEALL: + { + int enq = r == ID_CDROMMENU_ENQUEUEALL; + itemRecordList obj = {0, }; + saveCDToItemRecordList(cLetter, &obj, NULL); + mlSendToWinampStruct p; + p.type = ML_TYPE_CDTRACKS; + p.enqueue = enq | 2; + p.data = &obj; + SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_SENDTOWINAMP, (WPARAM)&p); + freeRecordList(&obj); + } + break; + case ID_CDROMMENU_EXTRACT_EXTRACTALL: + riphash = 0; + if (hItem) + { + if (hItem == MLNavCtrl_GetSelection(plugin.hwndLibraryParent)) + { + HWND hwnd = (HWND)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_GETCURRENTVIEW, 0); + if (hwnd && SendMessageW(hwnd, WM_EXTRACTDISC, cLetter, 0)) break; + } + + char devname[] = "X:\\"; + devname[0] = cLetter; + if (!GetVolumeInformationA(devname, NULL, 0, &riphash, NULL, NULL, NULL, 0)) riphash = 0; + if (riphash) riphash = ((0x00FFFFFF & riphash) | (cLetter << 24)); + MLNavItem_Select(plugin.hwndLibraryParent, hItem); + } + break; + case ID_CDROMMENU_EJECTCD: + { + CHAR cMode; + cMode = DriveManager_GetDriveMode(cLetter); + if (DM_MODE_READY != cMode) + { + wchar_t title[32] = {0}; + MessageBox(plugin.hwndLibraryParent, + WASABI_API_LNGSTRINGW((DM_MODE_RIPPING == cMode) ? IDS_ERROR_CD_RIP_IN_PROGRESS : IDS_ERROR_CD_BURN_IN_PROGRESS), + WASABI_API_LNGSTRINGW_BUF(IDS_CD_EJECT,title,32), 0); + return FALSE; + } + else DriveManager_Eject(cLetter, DM_EJECT_REMOVE); + } + break; + } + Sleep(100); + MSG msg; + while (PeekMessageW(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); //eat return + return 0; +} + +static DWORD resumeTick = 0; // this is cheating +static void Plugin_OnMLVisible(BOOL bVisible) +{ + if (bVisible) + { + DriveManager_Resume(TRUE); + resumeTick = GetTickCount(); + SendNotifyMessage(HWND_BROADCAST, uMsgBurnerNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent); + SendNotifyMessage(HWND_BROADCAST, uMsgRipperNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent); + SendNotifyMessage(HWND_BROADCAST, uMsgCopyNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent); + return; + } + else DriveManager_Suspend(); +} + +static HWND Plugin_OnViewCreate(HNAVITEM hItem, HWND hwndParent) +{ + if (hItem == hniMain) + { + return WASABI_API_CREATEDIALOGW(IDD_VIEW_RIPBURN, hwndParent, view_ripburnDialogProc); + } + else + { + DRIVE *pDrive = Plugin_GetDriveFromNavItem(hItem); + if (pDrive) return CreateContainerWindow(hwndParent, pDrive->cLetter, ((GetTickCount() - resumeTick) > 100)); + resumeTick = 0; + } + return NULL; +} +static BOOL Plugin_OnNavItemDelete(HNAVITEM hItem) +{ + DRIVE *pDrive = Plugin_GetDriveFromNavItem(hItem); + if (!pDrive) return FALSE; + DriveParam_UnregisterDrive(pDrive); + free(pDrive); + return TRUE; +} + +static BOOL Plugin_OnNavItemClick(HNAVITEM hItem, UINT nAction, HWND hwndParent) +{ + return FALSE; +} + +static INT Plugin_OnNavCustomDraw(HNAVITEM hItem, NAVITEMDRAW *pnicd, LPARAM lParam) +{ + static INT indent = 0; + DRIVE *pDrive; + + if (FALSE == DriveParam_IsValid(lParam)) + return FALSE; + + pDrive = (DRIVE*)lParam; + + if (0 == indent) indent = MLNavCtrl_GetIndent(plugin.hwndLibraryParent); + switch(pnicd->drawStage) + { + case NIDS_PREPAINT: + if (pnicd->prc->bottom > 0 && pnicd->prc->bottom > pnicd->prc->top) + { + HIMAGELIST himl; + INT realIndex, l, t, r; + MLIMAGELISTREALINDEX mlilRealIndex; + + himl = MLImageList_GetRealList(plugin.hwndLibraryParent, hmlilIcons); + + mlilRealIndex.cbSize = sizeof(MLIMAGELISTREALINDEX); + mlilRealIndex.hmlil = hmlilIcons; + mlilRealIndex.rgbBk = GetBkColor(pnicd->hdc); + mlilRealIndex.rgbFg = GetTextColor(pnicd->hdc); + + t = pnicd->prc->top + (pnicd->prc->bottom - pnicd->prc->top - ICON_SIZE_CY)/2; + l = pnicd->prc->left + (indent*pnicd->iLevel) + 3; + r = pnicd->prc->right; + + mlilRealIndex.mlilIndex = 0; + realIndex = ((NCS_SHOWICONS & g_navStyle) && himl && l < pnicd->prc->right) ? + MLImageList_GetRealIndex(plugin.hwndLibraryParent, &mlilRealIndex) : -1; + if (-1 != realIndex) // draw icon + { + if (ImageList_Draw(himl, realIndex, pnicd->hdc, l, t, ILD_NORMAL)) + { + ExcludeClipRect(pnicd->hdc, l, t, l + ICON_SIZE_CX, t + ICON_SIZE_CY); + l += (ICON_SIZE_CX + 5); + } + } + + pDrive->bEjectVisible = FALSE; + mlilRealIndex.mlilIndex = 1 + ((DM_MODE_READY == pDrive->cMode) ? pDrive->nBtnState : BTNSTATE_DISABLED); + realIndex = ((NCS_EX_SHOWEJECT & g_navStyle) && himl && (r - l) > (24 + 6 + ICON_SIZE_CX)) ? + MLImageList_GetRealIndex(plugin.hwndLibraryParent, &mlilRealIndex) : -1; + if (-1 != realIndex) + { + if (ImageList_Draw(himl, realIndex, pnicd->hdc, r - (ICON_SIZE_CX + 2), t, ILD_NORMAL)) + { + r -= (ICON_SIZE_CX + 2); + ExcludeClipRect(pnicd->hdc, r, t, r + ICON_SIZE_CX, t + ICON_SIZE_CY); + r -= 4; + pDrive->bEjectVisible = TRUE; + } + } + + if (*pDrive->szTitle && l < r) + { + RECT rt; + INT textH, textW; + COLORREF rgbOld(0), rgbBkOld(0); + + if (!pDrive->textSize || (pDrive->textOrigWidth > r-l-3 && pDrive->itemWidth > (pnicd->prc->right - pnicd->prc->left)) || + (LOWORD(pDrive->textSize) != pDrive->textOrigWidth && pDrive->itemWidth < (pnicd->prc->right - pnicd->prc->left))) + { + NAVITEM item; + item.cbSize = sizeof(NAVITEM); + item.mask = NIMF_TEXT; + item.hItem = hItem; + item.cchTextMax = sizeof(pDrive->szTitle)/sizeof(wchar_t); + item.pszText = pDrive->szTitle; + MLNavItem_GetInfo(plugin.hwndLibraryParent, &item); + { + if (pDrive->szTitle != item.pszText) + { + StringCchCopyW(pDrive->szTitle, sizeof(pDrive->szTitle)/sizeof(wchar_t), item.pszText); + } + if (!pDrive->textSize) + { + SetRect(&rt, 0, 0, 1, 1); + DrawTextW(pnicd->hdc, pDrive->szTitle, -1, &rt, DT_SINGLELINE | DT_CALCRECT); + pDrive->textOrigWidth = rt.right - rt.left; + } + SetRect(&rt, 0, 0, r - l - 3, 1); + textH = DrawTextW(pnicd->hdc, pDrive->szTitle, -1, &rt, DT_SINGLELINE|DT_CALCRECT|DT_END_ELLIPSIS|DT_MODIFYSTRING); + textW = rt.right - rt.left; + pDrive->textSize = (DWORD)MAKELONG(textW, textH); + } + } + else + { + textW = LOWORD(pDrive->textSize); + textH = HIWORD(pDrive->textSize); + } + + if (0 == (NCS_FULLROWSELECT & g_navStyle) && ((NIS_SELECTED | NIS_DROPHILITED) & pnicd->itemState)) + { + rgbOld = SetTextColor(pnicd->hdc, pnicd->clrText); + rgbBkOld = SetBkColor(pnicd->hdc, pnicd->clrTextBk); + } + + if (r > (l + textW + 7)) r = l + textW + 7; + + SetRect(&rt, l, pnicd->prc->top, r, pnicd->prc->bottom); + + t = pnicd->prc->top + (pnicd->prc->bottom - pnicd->prc->top - textH)/2; + ExtTextOutW(pnicd->hdc, rt.left + 2, t, ETO_CLIPPED | ETO_OPAQUE, &rt, pDrive->szTitle, lstrlenW(pDrive->szTitle), 0); + if (0 == (NCS_FULLROWSELECT & g_navStyle) && (NIS_FOCUSED & pnicd->itemState) && + 0 == (0x1 /*UISF_HIDEFOCUS*/ & (INT)SendMessageW(MLNavCtrl_GetHWND(plugin.hwndLibraryParent), 0x129 /*WM_QUERYUISTATE*/, 0, 0L))) + { + DrawFocusRect(pnicd->hdc, &rt); + } + ExcludeClipRect(pnicd->hdc, rt.left, rt.top, rt.right, rt.bottom); + + + if (0 == (NCS_FULLROWSELECT & g_navStyle) && ((NIS_SELECTED | NIS_DROPHILITED) & pnicd->itemState)) + { + if (rgbOld != pnicd->clrText) SetTextColor(pnicd->hdc, rgbOld); + if (rgbBkOld != pnicd->clrTextBk) SetBkColor(pnicd->hdc, rgbBkOld); + } + } + + pDrive->itemWidth = (WORD)(pnicd->prc->right - pnicd->prc->left); + + if (NCS_FULLROWSELECT & g_navStyle) + { + ExtTextOutW(pnicd->hdc, 0, 0, ETO_OPAQUE, pnicd->prc, L"", 0, 0); + return NICDRF_SKIPDEFAULT; + } + else ExcludeClipRect(pnicd->hdc, pnicd->prc->left, pnicd->prc->top, pnicd->prc->right, pnicd->prc->bottom); + } + break; + case NIDS_POSTPAINT: + break; + } + return NICDRF_DODEFAULT; +} + +static HNAVITEM hItemActive = NULL; + +static BOOL GetEjectBtnRect(HNAVITEM hItem, RECT *prc) +{ + NAVITEMGETRECT navRect; + navRect.fItem = FALSE; + navRect.hItem = hItem; + + if (!hItem || !prc || !MLNavItem_GetRect(plugin.hwndLibraryParent, &navRect)) return FALSE; + + navRect.rc.right -= 2; + navRect.rc.left = navRect.rc.right - ICON_SIZE_CX; + navRect.rc.top += (navRect.rc.bottom - navRect.rc.top - ICON_SIZE_CY)/2; + navRect.rc.bottom = navRect.rc.top + ICON_SIZE_CY; + + CopyRect(prc, &navRect.rc); + return TRUE; +} + +static INT_PTR Plugin_OnNavHitTest(HNAVITEM hItem, NAVHITTEST *pnavHitTest, LPARAM lParam) +{ + DRIVE *pDrive; + + if (FALSE == DriveParam_IsValid(lParam)) + return FALSE; + + pDrive = (DRIVE*)lParam; + + if ((NAVHT_ONITEMRIGHT | NAVHT_ONITEM) & pnavHitTest->flags) + { + RECT rb; + + if (pDrive->bEjectVisible && GetEjectBtnRect(hItem, &rb) && + pnavHitTest->pt.x >= rb.left && pnavHitTest->pt.x <= rb.right && + pnavHitTest->pt.y >= rb.top && pnavHitTest->pt.y <= rb.bottom) + { + pnavHitTest->flags = NAVHT_NOWHERE; + pnavHitTest->hItem = NULL; + } + } + return 1; +} + +static void CALLBACK NavButton_TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + DRIVE *pDrive; + POINT pt; + RECT rb; + + pDrive = (hItemActive) ? Plugin_GetDriveFromNavItem(hItemActive) : NULL; + if (!pDrive || (BYTE)BTNSTATE_NORMAL == pDrive->nBtnState || !pDrive->bEjectVisible || !GetEjectBtnRect(hItemActive, &rb)) + { + KillTimer(NULL, idEvent); + return; + } + + GetCursorPos(&pt); + MapWindowPoints(HWND_DESKTOP, MLNavCtrl_GetHWND(plugin.hwndLibraryParent), &pt, 1); + + + if (pt.x < rb.left || pt.x > rb.right || pt.y < rb.top || pt.y > rb.bottom) + { + NAVITEMINAVLIDATE inv; + + KillTimer(NULL, idEvent); + + inv.fErase = FALSE; + inv.hItem = hItemActive; + inv.prc = &rb; + + hItemActive = NULL; + pDrive->nBtnState = BTNSTATE_NORMAL; + + MLNavItem_Invalidate(plugin.hwndLibraryParent, &inv); + } +} + +static INT_PTR Plugin_OnNavSetCursor(HNAVITEM hItem, LPARAM lParam) +{ + POINT pt; + DRIVE *pDrive; + BYTE state; + RECT rb; + + if (FALSE == DriveParam_IsValid(lParam)) + return FALSE; + + pDrive = (DRIVE*)lParam; + + if (DM_MODE_READY != pDrive->cMode || !pDrive->bEjectVisible || !GetEjectBtnRect(hItem, &rb)) return -1; + + GetCursorPos(&pt); + + MapWindowPoints(HWND_DESKTOP, MLNavCtrl_GetHWND(plugin.hwndLibraryParent), &pt, 1); + if (pt.x >= rb.left && pt.x <= rb.right && pt.y >= rb.top && pt.y <= rb.bottom) + { + state = (BYTE)((0x8000 & GetAsyncKeyState( GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON)) ? + BTNSTATE_PRESSED : BTNSTATE_HILITED); + } + else state = BTNSTATE_NORMAL; + + if (pDrive->nBtnState != state) + { + + NAVITEMINAVLIDATE inv; + + if ((BYTE)BTNSTATE_PRESSED == pDrive->nBtnState && BTNSTATE_HILITED == state) + { + DriveManager_Eject(pDrive->cLetter, DM_EJECT_CHANGE); + } + + if (pDrive->timerId) + { + KillTimer(NULL, pDrive->timerId); + pDrive->timerId = 0; + } + if (hItemActive) + { + DRIVE *pDriveOld = Plugin_GetDriveFromNavItem(hItemActive); + if (pDriveOld) + { + RECT rb2; + if (pDriveOld->timerId) + { + KillTimer(NULL, pDriveOld->timerId); + pDriveOld->timerId = NULL; + } + if ((BYTE)BTNSTATE_NORMAL != pDriveOld->nBtnState && GetEjectBtnRect(hItemActive, &rb2)) + { + pDriveOld->nBtnState = BTNSTATE_NORMAL; + inv.fErase = FALSE; + inv.hItem = hItemActive; + inv.prc = &rb2; + MLNavItem_Invalidate(plugin.hwndLibraryParent, &inv); + } + hItemActive = NULL; + } + } + + if (BTNSTATE_NORMAL != state) + { + hItemActive = hItem; + pDrive->timerId = SetTimer(NULL, 0, NAVBUTTON_STATECHECK_DELAY, NavButton_TimerProc); + } + + pDrive->nBtnState = state; + + inv.fErase = FALSE; + inv.hItem = hItem; + inv.prc = &rb; + MLNavItem_Invalidate(plugin.hwndLibraryParent, &inv); + + } + + + return -1; +} + +static BOOL Plugin_OnConfig(void) +{ + SendMessageW(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&myPrefsItemCD, IPC_OPENPREFSTOPAGE); + return TRUE; +} + +static INT_PTR pluginMessageProc(int msg, INT_PTR param1, INT_PTR param2, INT_PTR param3) +{ + HNAVITEM hItem; + + if (msg >= ML_MSG_TREE_BEGIN && msg <= ML_MSG_TREE_END) + { + hItem = (msg < ML_MSG_NAVIGATION_FIRST) ? MLNavCtrl_FindItemById(plugin.hwndLibraryParent, param1) : (HNAVITEM)param1; + if (!hItem) return 0; + } else hItem = NULL; + + switch (msg) + { + case ML_MSG_TREE_ONCREATEVIEW: return (INT_PTR)Plugin_OnViewCreate(hItem, (HWND)param2); + case ML_MSG_NAVIGATION_ONDELETE: return (INT_PTR)Plugin_OnNavItemDelete(hItem); + case ML_MSG_NAVIGATION_ONCUSTOMDRAW: return (INT_PTR)Plugin_OnNavCustomDraw(hItem, (NAVITEMDRAW*)param2, (LPARAM)param3); + case ML_MSG_NAVIGATION_ONHITTEST: return (INT_PTR)Plugin_OnNavHitTest(hItem, (NAVHITTEST*)param2, (LPARAM)param3); + case ML_MSG_NAVIGATION_ONSETCURSOR: return (INT_PTR)Plugin_OnNavSetCursor(hItem, (LPARAM)param3); + case ML_MSG_NAVIGATION_CONTEXTMENU: + { + DRIVE *pDrive; + if (hniMain && (hItem == hniMain)) + return Root_OnContextMenu(hItem, (HWND)param2, MAKEPOINTS(param3)); + + //Plugin Item + pDrive = Plugin_GetDriveFromNavItem(hItem); + if (pDrive) + return Plugin_OnContextMenu(hItem, (HWND)param2, MAKEPOINTS(param3), pDrive->cLetter); + + return 0; + } + case ML_MSG_TREE_ONCLICK: return (INT_PTR)Plugin_OnNavItemClick(hItem, (UINT)param2, (HWND)param3); + case ML_MSG_CONFIG: return (INT_PTR)Plugin_OnConfig(); + case ML_MSG_MLVISIBLE: Plugin_OnMLVisible((BOOL)param1); break; + case ML_MSG_NOTOKTOQUIT: if (!Plugin_QueryOkToQuit()) { return TRUE; } break; + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////// +extern "C" winampMediaLibraryPlugin plugin = +{ + MLHDR_VER, + "nullsoft(ml_disc.dll)", + Init, + Quit, + pluginMessageProc, + 0, + 0, + 0, +}; + +extern "C" __declspec(dllexport) winampMediaLibraryPlugin *winampGetMediaLibraryPlugin() +{ + return &plugin; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/main.h b/Src/Plugins/Library/ml_disc/main.h new file mode 100644 index 00000000..285b8de6 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/main.h @@ -0,0 +1,222 @@ +#ifndef NULLSOFT_MAINH +#define NULLSOFT_MAINH + +#include "..\..\General\gen_ml/ml.h" +#include "..\..\General\gen_ml/ml_ipc_0313.h" + +#include "./config.h" +#include "./drivemngr.h" +#include "./drive.h" +#include "./medium.h" +#include "api__ml_disc.h" +#include "..\..\General\gen_ml/menu.h" + +#include "./copyfiles.h" +#include "./copyinternal.h" + +#include <shlobj.h> +#include <windows.h> +#include <commctrl.h> + +#ifndef LONGX86 +#ifdef _WIN64 + #define LONGX86 LONG_PTR +#else /*_WIN64*/ + #define LONGX86 LONG +#endif /*_WIN64*/ +#endif // LONGX86 + +#define OLD_AAC_CODEC mmioFOURCC('A','A','C',' ') + +#define BN_EX_GETTEXT 0x0FFF + +#define WM_EXTRACTDISC (WM_APP + 0x010) +#define WM_SHOWFILEINFO (WM_APP + 0x11) // (wParam)(UINT)WISF_, (lParam)(LPCWSTR)file(track)name (can be NULL to reset) +#define WM_QUERYFILEINFO (WM_APP + 0x12) +#define WM_TAGUPDATED (WM_APP + 0x13) // wParam = 0, lParam = (LPCWSTR)pszFileName + +#define VCM_CREATECOMMANDBAR (WM_APP + 0x20) +#define VCM_DESTROYCOMMANDBAR (WM_APP + 0x21) +#define VCM_GETCOMMANDBAR (WM_APP + 0x22) +#define VCM_GETMININFOENABLED (WM_APP + 0x23) +#define VCM_GETMININFOVISIBLE (WM_APP + 0x24) + + +typedef struct __CMDBARCREATESTRUCT +{ + HWND hwndOwner; + UINT resourceId; + DLGPROC fnDialogProc; + ULONG_PTR uData; +} CMDBARCREATESTRUCT; + +#define MSGRESULT(__hwnd, __result) { SetWindowLongPtrW((__hwnd), DWLP_MSGRESULT, ((LONGX86)(LONG_PTR)(__result))); return TRUE; } + +#define ViewContainer_CreateCmdBar(/*HWND*/ __hwndViewContainer, /*HWND*/ __hwndOwner, /*INT_PTR*/ __resourceId, /*DLGPROC*/ __fnDialogProc, /*ULONG_PTR*/ __uData)\ + {CMDBARCREATESTRUCT cs; cs.hwndOwner = (__hwndOwner); cs.resourceId = (__resourceId); cs.fnDialogProc = (__fnDialogProc); cs.uData = (__uData);\ + ((HWND)SNDMSG((__hwndViewContainer), VCM_CREATECOMMANDBAR, 0, (LPARAM)(&cs)));} + +#define ViewContainer_DestroyCmdBar(/*HWND*/ __hwndViewContainer)\ + ((BOOL)SNDMSG((__hwndViewContainer), VCM_DESTROYCOMMANDBAR, 0, 0L)) + +#define ViewContainer_GetCmdBar(/*HWND*/ __hwndViewContainer)\ + ((HWND)SNDMSG((__hwndViewContainer), VCM_GETCOMMANDBAR, 0, 0L)) + +#define ViewContainer_GetMiniInfoEnabled(/*HWND*/ __hwndViewContainer)\ + ((HWND)SNDMSG((__hwndViewContainer), VCM_GETMININFOENABLED, 0, 0L)) + +#define ViewContainer_GetMiniInfoVisible(/*HWND*/ __hwndViewContainer)\ + ((HWND)SNDMSG((__hwndViewContainer), VCM_GETMININFOVISIBLE, 0, 0L)) + + +extern winampMediaLibraryPlugin plugin; +extern LARGE_INTEGER freq; + +void CleanupDirectoryString(LPTSTR pszDirectory); +LPWSTR GetExtensionString(LPWSTR pszBuffer, INT cchBufferMax, DWORD fourcc); +HRESULT FormatFileName(LPTSTR pszTextOut, INT cchTextMax, LPCTSTR pszFormat, + INT nTrackNo, LPCTSTR pszArtist, + LPCTSTR pszAlbum, LPCTSTR pszTitle, + LPCTSTR pszGenre, LPCTSTR pszYear, + LPCTSTR pszTrackArtist, + LPCTSTR pszFileName, LPCTSTR pszDisc); + + +bool RegisteredEncoder(DWORD fourcc); + +extern C_Config *g_config; +extern HMENU g_context_menus; +extern C_Config *g_view_metaconf; + +#define DSF_CANRECORD 0x00010000 + +#define DSF_PLAYING 0x00000001 +#define DSF_RIPPING 0x00000002 +#define DSF_BURNING 0x00000004 +#define DSF_GETTINGINFO 0x00000008 + +typedef struct _DRIVE +{ + CHAR cLetter; + CHAR cMode; + WCHAR szTitle[64]; + DWORD textSize; + BOOL textOrigWidth; + WORD itemWidth; + BYTE nBtnState; + BOOL bEjectVisible; + UINT_PTR timerId; +} DRIVE; + + +typedef BOOL (CALLBACK *NAVITEMENUMPROC)(HNAVITEM hItem, DRIVE *pDrive, LPARAM param); + +DRIVE *Plugin_GetDriveFromNavItem(HNAVITEM hItem); +HNAVITEM Plugin_GetNavItemFromLetter(CHAR cLetter); +BOOL Plugin_EnumerateNavItems(NAVITEMENUMPROC callback, LPARAM param); +void Plugin_RegisterListener(HWND hwnd, UINT uMsg, CHAR cLetter); // active view can register itself to be notified about drive/medium changes if cLetter = 0 you will be notifed for all drives +void Plugin_UnregisterListener(HWND hwnd); +void Plugin_ShowRippingPreferences(void); +BOOL Plugin_IsExtractScheduled(CHAR cLetter); + +int getFileInfo(const char *filename, const char *metadata, char *dest, int len); +int getFileInfoW(const wchar_t *filename, const wchar_t *metadata, wchar_t *dest, int len); + +#define HF_DOMODAL 0x0001 +#define HF_ALLOWRESIZE 0x0010 + +HWND MLDisc_ShowHelp(HWND hParent, LPCWSTR pszWindowTitle, LPCWSTR pszCaption, LPCWSTR pszText, UINT uFlags); // returns hwnd only if not HF_DOMODAL + + +#define QBF_SHOW_CHECKBOX 0x00000001L +#define QBF_SHOW_EXTRA_BUTTON 0x00000002L +#define QBF_TOPMOST 0x00000100L +#define QBF_SETFOREGROUND 0x00000200L +#define QBF_BEEP 0x00000400L +#define QBF_FLASH 0x00000800L +#define QBF_DEFAULT_OK 0x00000000L +#define QBF_DEFAULT_CANCEL 0x00001000L +#define QBF_DEFAULT_EXTRA1 0x00002000L + + +typedef struct _QUESTIONBOX +{ + HWND hParent; // [in] + LPCTSTR pszIcon; // [in] + UINT uBeepType; // [in] + LPCTSTR pszTitle; // [in] accepts MAKEINTRESOURCE() as parameters. + LPCTSTR pszMessage; // [in] accepts MAKEINTRESOURCE() as parameters. + UINT uFlags; // [in] + LPCTSTR pszBtnOkText; // [in] accepts MAKEINTRESOURCE() as parameters. + LPCTSTR pszBtnCancelText; // [in] accepts MAKEINTRESOURCE() as parameters. + LPCTSTR pszCheckboxText; // [in] accepts MAKEINTRESOURCE() as parameters. + LPCTSTR pszBtnExtraText; // [in] accepts MAKEINTRESOURCE() as parameters. + BOOL checkboxChecked; // [in][out] +} QUESTIONBOX; + +INT_PTR MLDisc_ShowQuestionBox(QUESTIONBOX *pQuestionBox); // returns pressed button id; + +// cdrip.cpp +BOOL CALLBACK CDRipPrefsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); + +typedef struct +{ + char drive_letter; + + wchar_t *album; + wchar_t *artist; + wchar_t *genre; + wchar_t *year; + wchar_t *publisher; // record label + wchar_t *disc; // disc ##/## + wchar_t *comment; // notes from CDDB + wchar_t **composers; + wchar_t **conductors; + wchar_t **gracenoteFileIDs; + wchar_t **gracenoteExtData; + int total_length_bytes; + + int ntracks; // total number of tracks + wchar_t **tracks; // set these to NULL to not rip em + wchar_t **trackArtists; + + int *lengths; // lengths, in seconds + + wchar_t **filenames; // can be used internally to override output filenames + // (should always allocate, but leave NULL ptrs in the array) + wchar_t **tempFilenames; //where we are ripping to, we'll move at the end +} cdrip_params; + +void cdrip_extractFiles(cdrip_params *parms); + +int cdrip_isextracting(char drive); +void cdrip_stop_all_extracts(); + +//gracenote.cpp +void gracenoteInit(); +int gracenoteQueryFile(const char *filename); +void gracenoteCancelRequest(); +int gracenoteDoTimerStuff(); +void gracenoteSetValues(char *artist, char *album, char *title); +char *gracenoteGetTuid(); +int gracenoteIsWorking(); + +//view_ripburn.cpp +INT_PTR CALLBACK view_ripburnDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); + +// view_cdrom.cpp +void saveCDToItemRecordList(CHAR cLetter, itemRecordList *obj, char *album); +int cdrom_contextMenu(HWND parent, CHAR cLetter, HNAVITEM hItem); +void cdburn_appendItemRecord(itemRecordList *obj, char driveletter); + +HWND CreateContainerWindow(HWND hwndParent, CHAR cLetter, BOOL bQueryInfo); +HWND CreateWaitWindow(HWND hwndParent, CHAR cLetter); +HWND CreateInfoWindow(HWND hwndParent, CHAR cLetter); +HWND CreateCDViewWindow(HWND hwndParent, DM_NOTIFY_PARAM *phdr); +HWND CreateCDBurnWindow(HWND hwndParent, CHAR cLetter); +HWND CreateCDRipWindow(HWND hwndParent, CHAR cLetter); +HWND CreateCdDataViewWindow(HWND hwndParent, CHAR cLetter); + +BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam); + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/medium.cpp b/Src/Plugins/Library/ml_disc/medium.cpp new file mode 100644 index 00000000..38bfd259 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/medium.cpp @@ -0,0 +1,136 @@ +#include "./main.h" +#include "./medium.h" +#include "./drive.h" +#include "./resource.h" +//#include <primosdk.h> + +static int pType[] = +{ + IDS_STAMPED_DISC_OR_RECORDABLE_THAT_HAS_BEEN_RECORDED, + IDS_REWRITEABLE_DISC_HAS_DATA_BUT_KEPT_OPEN_FOR_APPEND, + IDS_REWRITEABLE_DISC_NOT_POSSIBLE_TO_APPEND_DATA, + IDS_BLANK_REWRITEABLE_DISC, +}; + +static int pFormat[] = +{ + IDS_MEDIA_BLANK_DISC, + IDS_MEDIA_DATA_MODE_1_DAO, + IDS_MEDIA_KODAK_PHOTO_CD, + IDS_MEDIA_DATA_MULTISESSION_MODE_1_CLOSED, + IDS_MEDIA_DATA_MULTISESSION_MODE_2_CLOSED, + IDS_MEDIA_DATA_MODE_2_DAO, + IDS_MEDIA_CDRFS, + IDS_MEDIA_PACKET_WRITING, + IDS_MEDIA_DATA_MULTISESSION_MODE_1_OPEN, + IDS_MEDIA_DATA_MULTISESSION_MODE_2_OPEN, + IDS_MEDIA_AUDIO_DAO_SAO_TAO, + IDS_MEDIA_AUDIO_REWRITEABLE_DISC_WITH_SESSION_NOT_CLOSED, + IDS_MEDIA_FIRST_TYPE_OF_ENHANCED_CD_ABORTED, + IDS_MEDIA_CD_EXTRA, + IDS_MEDIA_AUDIO_TAO_WITH_SESSION_NOT_WRITTEN, + IDS_MEDIA_FIRST_TRACK_DATA_OTHERS_AUDIO, + IDS_MEDIA_MIXED_MODE_MADE_TAO, + IDS_MEDIA_KODAK_PORTFOLIO, + IDS_MEDIA_VIDEO_CD, + IDS_MEDIA_CDi, + IDS_MEDIA_PLAYSTATION_SONY_GAMES, + IDS_MEDIA_OBSOLETE, + IDS_MEDIA_OBSOLETE_FOR_RESTRICTED_OVERWRITE_DVD, + IDS_MEDIA_DVDROM_OR_CLOSED_RECORDABLE, + IDS_MEDIA_INCREMENTAL_DVD_WITH_APPENDABLE_ZONE, + IDS_MEDIA_APPENDABLE_DVD_OF_ANY_TYPE, + IDS_MEDIA_DVDRAM_CARTRIDGE, + IDS_MEDIA_CD_OTHER_TYPE, +}; + +static wchar_t buffer[256]; + +LPCWSTR Medium_GetTypeString(DWORD nType) +{ + int index = -1; +#if 0 + switch(nType) + { + case PRIMOSDK_SILVER: index = 0; break; + case PRIMOSDK_COMPLIANTGOLD: index = 1; break; + case PRIMOSDK_OTHERGOLD: index = 2; break; + case PRIMOSDK_BLANK: index = 3; break; + } +#endif + return WASABI_API_LNGSTRINGW_BUF((-1 != index) ? pType[index] : IDS_UNKNOWN, buffer, + sizeof(buffer)/sizeof(wchar_t)); +} + +LPCWSTR Medium_GetPhysicalTypeString(DWORD nType) +{ + return Drive_GetTypeString(nType); +} + +LPCWSTR Medium_GetFormatString(DWORD nFormat) +{ + int index = -1; +#if 0 + switch(nFormat) + { + case PRIMOSDK_B1: index = 0; break; + case PRIMOSDK_D1: index = 1; break; + case PRIMOSDK_D2: index = 2; break; + case PRIMOSDK_D3: index = 3; break; + case PRIMOSDK_D4: index = 4; break; + case PRIMOSDK_D5: index = 5; break; + case PRIMOSDK_D6: index = 6; break; + case PRIMOSDK_D7: index = 7; break; + case PRIMOSDK_D8: index = 8; break; + case PRIMOSDK_D9: index = 9; break; + case PRIMOSDK_A1: index = 10; break; + case PRIMOSDK_A2: index = 11; break; + case PRIMOSDK_A3: index = 12; break; + case PRIMOSDK_A4: index = 13; break; + case PRIMOSDK_A5: index = 14; break; + case PRIMOSDK_M1: index = 15; break; + case PRIMOSDK_M2: index = 16; break; + case PRIMOSDK_M3: index = 17; break; + case PRIMOSDK_M4: index = 18; break; + case PRIMOSDK_M5: index = 19; break; + case PRIMOSDK_M6: index = 20; break; + case PRIMOSDK_F1: index = 21; break; + case PRIMOSDK_F2: index = 22; break; + case PRIMOSDK_F3: index = 23; break; + case PRIMOSDK_F4: index = 24; break; + case PRIMOSDK_F8: index = 25; break; + case PRIMOSDK_FA: index = 26; break; + case PRIMOSDK_GENERICCD: index = 27; break; + } +#endif + return WASABI_API_LNGSTRINGW_BUF((-1 != index) ? pFormat[index] : IDS_UNKNOWN, buffer, + sizeof(buffer)/sizeof(wchar_t)); +} + +BOOL Medium_IsRecordableType(DWORD nType) +{ + #if 0 + return (PRIMOSDK_COMPLIANTGOLD == nType || PRIMOSDK_BLANK == nType); +#else + return FALSE; +#endif +} + +BOOL Medium_IsRecordable(CHAR cLetter) +{ + wchar_t info[128] = {0}; + wchar_t name[] = L"cda://X.cda"; + DWORD result; + BOOL reloaded = FALSE; + + name[6] = cLetter; + + for(;;) + { + result = getFileInfoW(name, L"cdtype", info, sizeof(info)/sizeof(wchar_t)); + if (result || reloaded || !getFileInfoW(name, L"reloadsonic", NULL, 0)) break; + reloaded = TRUE; + } + + return (result) ? (!lstrcmpW(info, L"CDR") || !lstrcmpW(info, L"CDRW")) : FALSE; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/medium.h b/Src/Plugins/Library/ml_disc/medium.h new file mode 100644 index 00000000..fc0f5764 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/medium.h @@ -0,0 +1,17 @@ +#ifndef NULLSOFT_MLDISC_MEDIUM_HEADER +#define NULLSOFT_MLDISC_MEDIUM_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + +LPCWSTR Medium_GetTypeString(DWORD nType); +LPCWSTR Medium_GetPhysicalTypeString(DWORD nType); +LPCWSTR Medium_GetFormatString(DWORD nFormat); +BOOL Medium_IsRecordableType(DWORD nType); +BOOL Medium_IsRecordable(CHAR cLetter); + + +#endif // NULLSOFT_MLDISC_MEDIUM_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/menu.cpp b/Src/Plugins/Library/ml_disc/menu.cpp new file mode 100644 index 00000000..e01503f4 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/menu.cpp @@ -0,0 +1,25 @@ +#include "main.h" +#include "./menu.h" +#include "./resource.h" +#include "../gen_ml/ml_ipc_0313.h" + +INT Menu_TrackPopup(HMENU hMenu, UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm) +{ + if (NULL == hMenu) + return NULL; + + MLSKINNEDPOPUP popup; + ZeroMemory(&popup, sizeof(MLSKINNEDPOPUP)); + popup.cbSize = sizeof(MLSKINNEDPOPUP); + popup.hmenu = hMenu; + popup.fuFlags = fuFlags; + popup.x = x; + popup.y = y; + popup.hwnd = hwnd; + popup.lptpm = lptpm; + popup.skinStyle = SMS_USESKINFONT/*SMS_SYSCOLORS*/; + popup.customProc = NULL; + popup.customParam = 0; + + return (INT)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_TRACKSKINNEDPOPUPEX, &popup); +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/menu.h b/Src/Plugins/Library/ml_disc/menu.h new file mode 100644 index 00000000..d776685b --- /dev/null +++ b/Src/Plugins/Library/ml_disc/menu.h @@ -0,0 +1,13 @@ +#ifndef NULLOSFT_MLDISC_PLUGIN_MENU_HEADER +#define NULLOSFT_MLDISC_PLUGIN_MENU_HEADER + + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +INT Menu_TrackPopup(HMENU hMenu, UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm); + +#endif //NULLOSFT_MLDISC_PLUGIN_MENU_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/ml_disc.rc b/Src/Plugins/Library/ml_disc/ml_disc.rc new file mode 100644 index 00000000..a1dc5bc4 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/ml_disc.rc @@ -0,0 +1,939 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#include ""version.rc2""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_VIEW_WAIT DIALOGEX 0, 0, 291, 242 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + CONTROL "Show Info",IDC_BTN_SHOWINFO,"Button",BS_OWNERDRAW | WS_TABSTOP,251,231,40,11 + CTEXT "",IDC_LBL_TEXT,0,19,290,209,SS_CENTERIMAGE +END + +IDD_PREFSCDRIPFR DIALOGEX 0, 0, 272, 246 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "Tab1",IDC_TAB1,"SysTabControl32",WS_TABSTOP,0,0,271,246 +END + +IDD_PREFS_CDRIP1 DIALOGEX 0, 0, 260, 226 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Output Filenames",IDC_STATIC,4,3,256,108 + LTEXT "Specify the destination folder for ripped tracks:",IDC_STATIC,10,15,204,8 + EDITTEXT IDC_DESTPATH,10,26,198,13,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BUTTON1,208,26,44,13 + LTEXT "Specify the naming convention for ripped tracks:",IDC_STATIC,10,44,203,8 + EDITTEXT IDC_FILENAMEFMT,10,55,198,13,ES_AUTOHSCROLL + PUSHBUTTON "Format Help",IDC_BUTTON2,208,55,44,13 + CONTROL "Use uppercase file extensions (i.e. MP3 instead of mp3)",IDC_UPPERCASEEXT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,73,192,10 + LTEXT "",IDC_FMTOUT,10,87,244,18 + GROUPBOX "Tagging Settings",IDC_STATIC,4,115,256,110 + CONTROL "Automatically add ripped files to Library database",IDC_CHECK_ML, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,128,193,10 + CONTROL "Automatically add tags with metadata to ripped files",IDC_TAGFILES, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,141,183,10 + CONTROL "Automatically calculate replay gain",IDC_AUTO_RG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,154,126,10 + CONTROL "Write track numbers as track/total (e.g. 12/15)",IDC_TOTAL_TRACKS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,167,167,10 + LTEXT "When tagging ripped CDs, make track numbers start with:",IDC_STATIC,10,181,186,8 + EDITTEXT IDC_EDIT2,198,179,25,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Add the following to the comment field of ripped files:",IDC_STATIC,10,195,174,8 + EDITTEXT IDC_EDIT1,10,206,243,13,ES_AUTOHSCROLL +END + +IDD_PREFS_CDRIP2 DIALOGEX 0, 0, 260, 226 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Encoding Format",IDC_STATIC,4,3,256,44 + LTEXT "Select the format you wish to encode to:",IDC_STATIC,12,15,240,11 + COMBOBOX IDC_ENCFORMAT,20,27,233,116,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_ENC_CONFIG,"Static",SS_BLACKRECT | NOT WS_VISIBLE,4,51,255,167 +END + +IDD_VIEW_CDROM_EXTRACT DIALOGEX 0, 0, 269, 156 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU +CAPTION "Ripping from CD..." +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + GROUPBOX "Current Track",IDC_CTFRAME,4,7,261,70 + EDITTEXT IDC_CURTRACK,16,18,240,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP + CONTROL "",IDC_STATUS,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,16,31,240,18 + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",WS_BORDER,16,52,240,14 + GROUPBOX "All Tracks",IDC_STATIC,4,72,261,62 + LTEXT "",IDC_STATUS2,16,88,240,22 + CONTROL "Progress1",IDC_PROGRESS2,"msctls_progress32",WS_BORDER,16,114,240,14 + PUSHBUTTON "Hide Window",IDCANCEL,76,139,57,13 + PUSHBUTTON "Cancel",IDC_BUTTON1,137,139,57,13 +END + +IDD_PREFS_CDRIP4 DIALOGEX 0, 0, 260, 226 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Playlist Creation Settings",IDC_STATIC,4,3,256,152 + LTEXT "When Winamp completes ripping an entire CD, it can automatically generate a playlist of the ripped tracks.",IDC_STATIC,10,15,243,18 + LTEXT "Create the following playlists:",IDC_STATIC,10,37,230,10 + CONTROL "Library playlist",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,49,80,10 + CONTROL ".M3U playlist",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,62,57,10 + CONTROL "Use extended M3U playlist format",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,74,121,10 + CONTROL ".PLS playlist",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,86,53,10 + LTEXT "Specify the naming convention for M3U and PLS playlists:",IDC_STATIC,10,102,183,8 + EDITTEXT IDC_FILENAMEFMT,10,114,196,13,ES_AUTOHSCROLL + PUSHBUTTON "Format Help",IDC_BUTTON2,207,114,45,13 + LTEXT "",IDC_FMTOUT,13,131,242,18 +END + +IDD_VIEW_CDROM_EX2 DIALOGEX 0, 0, 291, 242 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "",IDC_CDINFO,1,0,288,18,SS_NOPREFIX + CONTROL "List4",IDC_LIST2,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_TABSTOP,0,19,290,209 + CONTROL "Rip Options",IDC_RIPOPTS,"Button",BS_OWNERDRAW | WS_TABSTOP,0,231,48,11 + CONTROL "Cancel Rip",IDC_CANCEL_RIP,"Button",BS_OWNERDRAW | WS_TABSTOP,52,231,44,11 + CONTROL "Show Info",IDC_BTN_SHOWINFO,"Button",BS_OWNERDRAW | WS_TABSTOP,251,231,40,11 +END + +IDD_VIEW_CDROM_BURN DIALOGEX 0, 0, 291, 242 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN +EXSTYLE WS_EX_ACCEPTFILES | WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "",IDC_CDINFO,"Static",SS_LEFTNOWORDWRAP | SS_NOPREFIX | WS_GROUP,1,0,255,17 + CONTROL 1101,IDC_LOGO,"Static",SS_BITMAP | SS_NOTIFY | SS_REALSIZEIMAGE,260,2,31,15 + CONTROL "List4",IDC_LIST2,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_TABSTOP,0,19,290,209 + CONTROL "Add...",IDC_ADD,"Button",BS_OWNERDRAW | WS_TABSTOP,0,231,40,11 + CONTROL "Burn Options",IDC_BURN_OPTS,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,0,231,46,11 + CONTROL "Clear",IDC_CLEAR,"Button",BS_OWNERDRAW | WS_TABSTOP,42,231,40,11 + CONTROL "Cancel Burn",IDC_CANCEL_BURN,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,51,231,46,11 + CONTROL "Burn",IDC_BURN,"Button",BS_OWNERDRAW | WS_TABSTOP,84,231,40,11 + CONTROL "Show Info",IDC_BTN_SHOWINFO,"Button",BS_OWNERDRAW | WS_TABSTOP,251,231,40,11 +END + +IDD_BURN_ADD_STATUS DIALOGEX 0, 0, 160, 42 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "CD Burner" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Adding tracks to burner...",IDC_STAT,7,7,146,8 + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",WS_BORDER,7,21,146,14 +END + +IDD_BURN DIALOGEX 0, 0, 251, 143 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Burn speed:",IDC_STATIC,7,9,39,8 + COMBOBOX IDC_COMBO1,50,7,71,154,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Want to burn at your computer's maximum speed?",IDC_PRO1,7,23,168,8 + CONTROL "Click here",IDC_PRO2,"Button",BS_OWNERDRAW | WS_TABSTOP,176,23,35,10 + CONTROL "Enable Burn-proof mode (when available)",IDC_CHECK2, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,35,145,10 + LTEXT "Burn-proof mode is supported on newer CD burners and helps ensure that the burn does not fail. The downside of burn-proof mode is higher memory use. Burn-proof mode is highly recommended.",IDC_STATIC,20,47,224,26 + CONTROL "Test mode (do not actually write to media)",IDC_CHECK1, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,77,147,10 + LTEXT "Test mode lets you go through the burning process without actually writing to the physical CD. This can be useful to test system performance without risking making unusable media.",IDC_STATIC,20,91,222,26 + DEFPUSHBUTTON "Burn",IDOK,71,123,50,13 + PUSHBUTTON "Cancel",IDCANCEL,124,123,50,13 +END + +IDD_WAITFORCDR DIALOGEX 0, 0, 186, 63 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Waiting for blank CD..." +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "",IDC_TEXT,7,7,172,8 + PUSHBUTTON "Cancel",IDCANCEL,64,42,50,14 +END + +/* IDD_UPSELL_RIPPING DIALOGEX 0, 0, 223, 93 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Rip CDs faster in MP3" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "With Winamp Pro you can:\n\t- Rip in MP3\n\t- Burn and Rip Faster\n\t- Support Winamp",IDC_STATIC,7,7,209,33 + LTEXT "The free version of Winamp will only rip CDs at 8x speed in AAC.",IDC_STATIC,7,43,209,10 + CONTROL "Never show me this again",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,57,97,10 + PUSHBUTTON "More Info",IDC_BUTTON1,7,73,60,13 + PUSHBUTTON "Rip at 8x in AAC",IDOK,70,73,60,13 + PUSHBUTTON "Cancel Rip",IDCANCEL,166,73,50,13 +END */ + +IDD_NOBURN DIALOGEX 0, 0, 300, 58 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Cannot burn track" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Skip File",IDOK,192,41,50,13 + PUSHBUTTON "Cancel",IDCANCEL,246,41,50,13 + EDITTEXT IDC_MESSAGE2,4,4,292,32,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER +END + +IDD_VIEW_RIPBURN DIALOGEX 0, 0, 294, 236 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN +EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CTEXT "Available drives:",IDC_LBL_DRIVES,0,2,66,12,SS_CENTERIMAGE + LTEXT "Drive Info:",IDC_LBL_INFO_DRIVE,70,2,222,69 + LISTBOX IDC_LIST_DRIVES,0,18,66,205,LBS_SORT | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | NOT WS_BORDER | WS_TABSTOP + LTEXT "Drive Letter:",IDC_LBL_DRIVE_LETTER,80,18,58,8,NOT WS_VISIBLE + CONTROL "",IDC_LBL_DRIVE_LETTER_VAL,"Static",SS_LEFTNOWORDWRAP | SS_ENDELLIPSIS | NOT WS_VISIBLE | WS_GROUP,140,18,150,8 + LTEXT "Description:",IDC_LBL_DRIVE_DESCRIPTION,80,28,58,8,NOT WS_VISIBLE + CONTROL "",IDC_LBL_DRIVE_DESCRIPTION_VAL,"Static",SS_LEFTNOWORDWRAP | SS_ENDELLIPSIS | NOT WS_VISIBLE | WS_GROUP,140,28,150,8 + LTEXT "Bus type:",IDC_LBL_DRIVE_BUS,80,38,58,8,NOT WS_VISIBLE + CONTROL "",IDC_LBL_DRIVE_BUS_VAL,"Static",SS_LEFTNOWORDWRAP | SS_ENDELLIPSIS | NOT WS_VISIBLE | WS_GROUP,140,38,150,8 + LTEXT "Supported Types:",IDC_LBL_DRIVE_TYPES,80,48,58,8,NOT WS_VISIBLE + LTEXT "",IDC_LBL_DRIVE_TYPES_VAL,140,48,150,16,SS_ENDELLIPSIS | NOT WS_VISIBLE + LTEXT "Medium Info:",IDC_LBL_INFO_MEDIUM,70,77,222,146 +// LTEXT "Medium information is not available due to the Sonic Burning engine not being installed.\n\nPlease install the Sonic Burning engine if you want to see medium information.",IDC_LBL_MEDIUM_UPDATE,110,112,150,51 + LTEXT "This feature is not available in this Winamp build.\n\nDrive info and CD Burning will return for the next release.",IDC_LBL_MEDIUM_UPDATE,110,112,150,51 + LTEXT "Type:",IDC_LBL_MEDIUM_TYPE,80,91,50,8,NOT WS_VISIBLE + CONTROL "",IDC_LBL_MEDIUM_DISC_VAL,"Static",SS_LEFTNOWORDWRAP | SS_ENDELLIPSIS | NOT WS_VISIBLE | WS_GROUP,140,91,150,8 + LTEXT "Format:",IDC_LBL_MEDIUM_FORMAT,80,101,50,8,NOT WS_VISIBLE + CONTROL "",IDC_LBL_MEDIUM_FORMAT_VAL,"Static",SS_LEFTNOWORDWRAP | SS_ENDELLIPSIS | NOT WS_VISIBLE | WS_GROUP,140,101,150,8 + LTEXT "Tracks #:",IDC_LBL_MEDIUM_TRACKN,80,111,50,8,NOT WS_VISIBLE + CONTROL "",IDC_LBL_MEDIUM_TRACKN_VAL,"Static",SS_LEFTNOWORDWRAP | SS_ENDELLIPSIS | NOT WS_VISIBLE | WS_GROUP,140,111,150,8 + LTEXT "Capacity:",IDC_LBL_MEDIUM_CAPACITY,80,121,50,8,NOT WS_VISIBLE + CONTROL "",IDC_LBL_MEDIUM_CAPACITY_VAL,"Static",SS_LEFTNOWORDWRAP | SS_ENDELLIPSIS | NOT WS_VISIBLE | WS_GROUP,140,121,150,8 + LTEXT "Recordable:",IDC_LBL_MEDIUM_RECORDABLE,80,135,50,8,NOT WS_VISIBLE + CONTROL "",IDC_LBL_MEDIUM_RECORDABLE_VAL,"Static",SS_LEFTNOWORDWRAP | SS_ENDELLIPSIS | NOT WS_VISIBLE | WS_GROUP,140,135,150,8 + LTEXT "Erasable:",IDC_LBL_MEDIUM_ERASEABLE,80,145,50,8,NOT WS_VISIBLE + CONTROL "",IDC_LBL_MEDIUM_ERASEABLE_VAL,"Static",SS_LEFTNOWORDWRAP | SS_ENDELLIPSIS | NOT WS_VISIBLE | WS_GROUP,140,145,150,8 + LTEXT "Additional Info:",IDC_LBL_MEDIUM_ADDINFO,80,159,50,8,NOT WS_VISIBLE + LTEXT "",IDC_LBL_MEDIUM_ADDINFO_VAL,140,159,149,8,SS_ENDELLIPSIS | NOT WS_VISIBLE + CONTROL "Refresh List",IDC_BTN_REFRESH,"Button",BS_OWNERDRAW | WS_TABSTOP,0,225,67,11 +END + +IDD_VIEW_CONTAINER DIALOGEX 0, 0, 276, 166 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN +END + +IDD_VIEW_CDROM DIALOGEX 0, 0, 291, 242 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "",IDC_CDINFO,1,0,173,18,SS_NOPREFIX + LTEXT "",IDC_CDINFO2,174,0,116,18 + CONTROL "List4",IDC_LIST2,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_TABSTOP,0,19,290,209 + CONTROL "Play",IDC_BUTTON_PLAY,"Button",BS_OWNERDRAW | WS_TABSTOP,0,231,35,11 + CONTROL "Enqueue",IDC_BUTTON_ENQUEUE,"Button",BS_OWNERDRAW | WS_TABSTOP,39,231,38,11 + CONTROL "Rip",IDC_BUTTON_EXTRACT,"Button",BS_OWNERDRAW | WS_TABSTOP,81,231,32,11 + CONTROL "Eject CD",IDC_BUTTON_EJECT,"Button",BS_OWNERDRAW | WS_TABSTOP,117,231,42,11 + CONTROL "Show Info",IDC_BTN_SHOWINFO,"Button",BS_OWNERDRAW | WS_TABSTOP,251,231,40,11 +END + +IDD_VIEW_INFO DIALOGEX 0, 0, 291, 242 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + CONTROL "Show Info",IDC_BTN_SHOWINFO,"Button",BS_OWNERDRAW | WS_TABSTOP,251,231,40,11 + CTEXT "\n\n\nAnother instance of Winamp has locked this drive.\nYou will need to wait or cancel the operation.",IDC_LBL_TEXT,0,19,290,209 +END + +IDD_VIEW_CDROM_DATA DIALOGEX 0, 0, 478, 474 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN +END + +IDD_COMMANDBAR_DATA DIALOGEX 0, 0, 291, 14 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "",IDC_BTN_PLAYEX,0,0,75,14,WS_GROUP + PUSHBUTTON "Copy...",IDC_BTN_COPY,83,0,50,14 + PUSHBUTTON "",IDC_BTN_EJECT,265,0,24,14 + CONTROL "",IDC_LBL_STATUS,"Static",SS_LEFTNOWORDWRAP | SS_NOPREFIX | SS_CENTERIMAGE | SS_WORDELLIPSIS | WS_GROUP,137,0,108,14 +END + +IDD_FILECOPY_PREPARE DIALOGEX 0, 0, 279, 206 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Copy Files" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "",IDC_BTN_OPTIONS,4,43,59,14 + DEFPUSHBUTTON "OK",IDOK,169,43,50,14 + PUSHBUTTON "Cancel",IDCANCEL,225,43,50,14 + EDITTEXT IDC_EDT_PATH,10,83,259,13,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_BTN_BROWSE,219,98,50,14 + CONTROL "Add files to Library database",IDC_CHK_ADDTOMLDB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,123,259,10 + CONTROL "Use custom naming",IDC_CHK_CUSTOMNAME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,135,259,10 + EDITTEXT IDC_EDT_NAMEFORMAT,20,147,249,13,ES_AUTOHSCROLL + PUSHBUTTON "Help",IDC_BTN_HELP,219,179,50,14 + LTEXT "",IDC_LBL_MESSAGE,68,6,207,28 + CONTROL "Destination folder:",IDC_STATIC,"Static",SS_SIMPLE | WS_GROUP,10,73,259,8 + GROUPBOX "",IDC_GRP_OPTIONS,4,65,271,135 + CONTROL "",IDC_PIC_LOGO,"Static",SS_BITMAP | SS_REALSIZEIMAGE,10,6,15,13 + CONTROL "",IDC_LBL_EXAMPLE,"Static",SS_LEFTNOWORDWRAP | SS_ENDELLIPSIS | WS_GROUP,56,162,211,8 + CONTROL "Example:",IDC_LBL_EXAMPLE_TITLE,"Static",SS_SIMPLE | WS_GROUP,22,162,30,8 + CONTROL "Free:",IDC_LBL_FREE_TITLE,"Static",SS_SIMPLE | WS_GROUP,12,97,18,8 + CONTROL "Required:",IDC_LBL_REQUIRED_TITLE,"Static",SS_SIMPLE | WS_GROUP,12,106,32,8 + LTEXT "",IDC_LBL_FREE,49,97,113,8 + LTEXT "",IDC_LBL_REQUIRED,49,106,113,8 +END + +IDD_FILECOPY_PROGRESS DIALOGEX 0, 0, 279, 63 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU +CAPTION "Copy Files" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,225,43,50,14 + CONTROL "",IDC_PIC_LOGO,"Static",SS_BITMAP | SS_REALSIZEIMAGE,10,6,15,13 + LTEXT "",IDC_LBL_TASK,68,6,207,9 + CONTROL "",IDC_PRG_TOTAL,"msctls_progress32",WS_BORDER,68,27,207,10 + LTEXT "",IDC_LBL_OPERATION,68,16,207,9 +END + +IDD_SIMPLEHELP DIALOGEX 0, 0, 148, 123 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_NOFAILCREATE | WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Close",IDCANCEL,90,102,50,14 + EDITTEXT IDC_EDT_TEXT,7,39,133,50,ES_MULTILINE | ES_READONLY | ES_WANTRETURN | NOT WS_BORDER | WS_VSCROLL,WS_EX_STATICEDGE + LTEXT "",IDC_LBL_CAPTION,7,7,133,24 +END + +IDD_FILECOPY_QUESTION DIALOGEX 0, 0, 248, 66 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,136,46,50,14 + PUSHBUTTON "Cancel",IDCANCEL,192,46,50,14 + LTEXT "Label",IDC_LBL_MESSAGE,53,6,189,23 + CONTROL "",IDC_CHECKBOX1,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,6,35,236,10 + PUSHBUTTON "Extra1",IDC_BTN_EXTRA1,80,46,50,14,NOT WS_VISIBLE + ICON 32514,IDC_PIC_ICON,6,6,21,20,SS_REALSIZEIMAGE +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_LISTITEM_CDDRIVE BITMAP "resources\\cdrom_32x32_24.bmp" +IDB_LISTBOX_BACK BITMAP "resources\\listbox_back_2x68x24.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_CONTEXTMENUS MENU +BEGIN + POPUP "ExtractMenu" + BEGIN + MENUITEM "CD ripping preferences...", 40001 + MENUITEM SEPARATOR + MENUITEM "Rip all tracks", 40002 + MENUITEM "Rip selected tracks", 40003 + END + POPUP "CdromMenu" + BEGIN + MENUITEM "Play selection\tEnter", 40004 + MENUITEM "Enqueue selection\tShift+Enter", 40005 + MENUITEM SEPARATOR + MENUITEM "Select All\tCtrl+A", ID_CDROMMENU_SELECTALL + MENUITEM SEPARATOR + MENUITEM "Play all tracks", 40006 + MENUITEM "Enqueue all tracks", 40007 + MENUITEM SEPARATOR + MENUITEM "Edit &CD Info...\tAlt+3", 40008 + POPUP "Rip" + BEGIN + MENUITEM "Rip selected track(s)", 40009 + MENUITEM "Rip all tracks", 40010 + MENUITEM SEPARATOR + MENUITEM "CD ripping preferences...", 40011 + END + END + POPUP "CdromMenu2" + BEGIN + MENUITEM "Play audio CD", 40006 + MENUITEM "Enqueue audio CD", 40007 + MENUITEM SEPARATOR + MENUITEM "Rip audio CD", 40010 + MENUITEM "CD ripping preferences...", 40011 + MENUITEM SEPARATOR + MENUITEM "Eject CD", 40012 + MENUITEM SEPARATOR + MENUITEM "Help", ID_CDROMMENU_EXTRACT_HELP + END + POPUP "BurnAddMenu" + BEGIN + MENUITEM "Files...", 40013 + MENUITEM "Folder...", 40014 + MENUITEM SEPARATOR + MENUITEM "Current playlist", 40015 + END + POPUP "BurnContextMenu" + BEGIN + MENUITEM "Play selection\tEnter", 40016 + MENUITEM "Enqueue selection\tShift+Enter", 40017 + MENUITEM SEPARATOR + MENUITEM "Select all\tCtrl+A", ID_BURNCONTEXTMENU_SELECTALL + MENUITEM SEPARATOR + MENUITEM "Move selected items up\tAlt+Up", 40018 + MENUITEM "Move selected items down\tAlt+Down", 40019 + MENUITEM SEPARATOR + MENUITEM "Remove selected items\tDel", 40020 + MENUITEM SEPARATOR + MENUITEM "Burn...", 40021 + END + POPUP "RipOptions" + BEGIN + POPUP "Priority" + BEGIN + MENUITEM "Highest", 40022 + MENUITEM "Above normal", 40023 + MENUITEM "Normal", 40024 + MENUITEM "Below normal", 40025 + MENUITEM "Lowest", 40026 + MENUITEM "Idle", 40027 + END + MENUITEM SEPARATOR + MENUITEM "&Ripping Status Window", 40028 + MENUITEM SEPARATOR + MENUITEM "&Eject CD when complete", 40029 + MENUITEM "&Play tracks when complete", 40030 + MENUITEM "&Close view when complete", 40031 + END + POPUP "BurnOptions" + BEGIN + MENUITEM "&Burning Status Window", 40028 + MENUITEM SEPARATOR + MENUITEM "&Eject CD when complete", 40029 + MENUITEM "&Close view when complete", 40031 + MENUITEM "&Add CD titles to local DB when complete", 40032 + END + POPUP "Navigation" + BEGIN + MENUITEM "&Preferences", ID_NAVIGATION_PREFERENCES + MENUITEM SEPARATOR + MENUITEM "Help", ID_NAVIGATION_HELP + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_VIEW_CDROM_EXTRACT, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 265 + BOTTOMMARGIN, 152 + END + + IDD_NOBURN, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 296 + TOPMARGIN, 4 + BOTTOMMARGIN, 54 + END + + IDD_VIEW_CONTAINER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 269 + TOPMARGIN, 7 + BOTTOMMARGIN, 159 + END + + IDD_VIEW_CDROM_DATA, DIALOG + BEGIN + RIGHTMARGIN, 477 + BOTTOMMARGIN, 472 + END + + IDD_FILECOPY_PREPARE, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 275 + VERTGUIDE, 10 + VERTGUIDE, 20 + VERTGUIDE, 49 + VERTGUIDE, 68 + VERTGUIDE, 269 + TOPMARGIN, 6 + BOTTOMMARGIN, 200 + HORZGUIDE, 57 + HORZGUIDE, 97 + HORZGUIDE, 106 + END + + IDD_FILECOPY_PROGRESS, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 275 + VERTGUIDE, 68 + TOPMARGIN, 6 + BOTTOMMARGIN, 57 + END + + IDD_SIMPLEHELP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 140 + TOPMARGIN, 7 + BOTTOMMARGIN, 116 + END + + IDD_FILECOPY_QUESTION, DIALOG + BEGIN + LEFTMARGIN, 6 + RIGHTMARGIN, 242 + TOPMARGIN, 6 + BOTTOMMARGIN, 60 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCELERATOR_VIEW ACCELERATORS +BEGIN + VK_RETURN, ID_COPY_SELECTION, VIRTKEY, CONTROL, NOINVERT + "E", ID_EJECT_DISC, VIRTKEY, SHIFT, CONTROL, NOINVERT + "I", ID_MINIINFO_SHOW, VIRTKEY, CONTROL, NOINVERT +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_NULLSOFT_RIP_AND_BURN "Nullsoft Rip & Burn v%d.%02d" + 65535 "{2C913A2F-CD49-40a1-8F1A-8EF7C2A22229}" +END + +STRINGTABLE +BEGIN + IDS_ERROR_WRITING_TEMP_BURN_LIST "Error writing temporary burning list." + IDS_ERROR "Error" + IDS_BURN_X_TRACKX_ON_X "Burn %d %s on %c:" + IDS_X_OF_X_SECTORS_FREE "%d of %d sectors free" + IDS_GET_PRO_FOR_BURN_HIGHER_THAN_2X + "In order to use more than 2x burning, you must purchase Winamp Pro.\nWould you like information on purchasing Winamp Pro?" +// IDS_WINAMP_PRO_FEATURE "Winamp Pro Feature" + IDS_NEED_TO_ADD_SOME_TRACKS_TO_BURN + "You need to add some tracks to burn first!" + IDS_TOTAL_LENGTH_IS_BIGGER_THAN_MEDIA_CAPACITY + "The total length of the tracks in the list is bigger than the capacity of the blank CD in the drive!\n\nYou need to remove %01d:%02ds from the list." + IDS_BURNING "Burning..." + IDS_CANCEL_BURN "Cancel Burn" + IDS_NO_BLANK_CDR_IN_DRIVE "No blank CD-R in drive.\n" + IDS_X_CAPACITY_DETAILS "%s - Capacity: %01d:%02d.\n" + IDS_USED_X_X_TRACKS "Used: %01d:%02d (%d %s)" + IDS_AVAILABLE_X_X ", Available: %01d:%02d." + IDS_X_OVER_CAPACITY_REMOVE_X_TRACKS + ", %01d:%02d over capacity. Please remove %d tracks." +END + +STRINGTABLE +BEGIN + IDS_FILE_X_CANNOT_BE_BURNED_REASON_NOT_FOUND + "The file\n%s\ncannot be burned.\nReason: File not found." + IDS_FILE_X_CANNOT_BE_BURNED_REASON_FILETYPE_NOT_REGISTERED + "The file\n%s\ncannot be burned.\nReason: The file type (extension %s) is not registered with Winamp" + IDS_FILE_X_CANNOT_BE_BURNED_REASON_X + "The file\n%s\ncannot be burned.\nReason: %s" + IDS_VIDEO_FILES_CANNOT_BE_BURNED "Video files cannot be burned" + IDS_NOT_AN_AUDIO_FILE "Not an audio file" + IDS_FILE_CANNOT_BE_BURNED "The file\n%s\ncannot be burned." + IDS_TRACK_NUMBER "Track #" + IDS_TITLE "Title" + IDS_LENGTH "Length" + IDS_STATUS "Status" + IDS_CANCELLING "Cancelling..." + IDS_BURNING_AUDIO_CANCELLING + "Burning Audio CD...\nCurrent Operation: Canceling..." + IDS_BURNING_AUDIO_FINISHING + "Burning Audio CD...\nCurrent Operation: Finishing..." + IDS_BURNING_AUDIO_DATA_PREP_FINISHED + "Burning Audio CD...\nCurrent Operation: Data preparation finished." + IDS_BURNING_AUDIO_VERIFYING_FILES + "Burning Audio CD...\nCurrent Operation: Verifying files..." + IDS_BURNING_AUDIO_VERIFICATION_COMPLETED + "Burning Audio CD...\nCurrent Operation: Verification completed." +END + +STRINGTABLE +BEGIN + IDS_OPENING_DISC_WRITING_LEAD_IN "Opening disc / Writing Lead-In..." + IDS_CLOSING_DISC_WRITING_LEAD_OUT "Closing disc / Writing Lead-Out..." + IDS_BURNING_AUDIO_CURRENT_OPERATION + "Burning Audio CD... ( %d%% completed)\nCurrent Operation: %s" + IDS_BURNING_AUDIO_CD_PREP_DATA + "Burning Audio CD... ( %d%% completed)\nCurrent Operation: Preparing data..." + IDS_BURNING_AUDIO_BURNING_DATA + "Burning Audio CD... ( %d%% completed)\nCurrent Operation: Burning data..." + IDS_CLOSE "Close" + IDS_AUDIO_CD_BURNED_SUCCESSFULLY "Audio CD burned successfully." + IDS_BURN_ABORTED_BY_USER "Burning aborted by user." + IDS_BURNING_FAILED "Burning failed." + IDS_BURNING_COMPLETED_STATUS_X "Burning completed.\nStatus: %s" + IDS_ALL_FILES "All files" + IDS_ADD_FILES_TO_BURNING_LIST "Add file(s) to burning list" + IDS_CHOOSE_A_FOLDER_TO_ADD_TO_BURNING_LIST + "Choose a folder to add to the burning list" + IDS_SURE_YOU_WANT_TO_CLEAR_BURNING_LIST + "Are you sure you want to clear the burning list?" + IDS_CONFIRMATION "Confirmation" + IDS_BURNING_ "Burning" +END + +STRINGTABLE +BEGIN + IDS_PREPARING "Preparing" + IDS_FINISHED "Finished" + IDS_PREPARED "Prepared" + IDS_SKIPPED "Skipped" + IDS_SCHEDULED "Scheduled" + IDS_CHECKING_LICENSE "Checking License..." + IDS_LICENSED "Licensed" + IDS_CANCELLED "Cancelled" + IDS_FAILED "Failed" + IDS_BAD_FILENAME "Bad filename" + IDS_UNABLE_TO_OPEN_FILE "Unable to open file" + IDS_CACHE_WRITE_FAILED "Cache write failed" + IDS_UNABLE_TO_FIND_DECODER "Unable to find decoder" + IDS_CANNOT_ADD_TO_THE_DISC "Cannot add to the disc" + IDS_CACHE_READ_FAILED "Cache read failed" + IDS_UNKNOWN_ERROR "Unknown Error" +END + +STRINGTABLE +BEGIN + IDS_ADDING_TRACKS_TO_BURNER_TOTAL_LENGTH_X + "Adding tracks to burner. Total length: %01d:%02d" + IDS_PLEASE_INSERT_BLANK_RECORDABLE_CD + "Please insert a blank recordable CD in drive %c:" + IDS_COMPLETED "Completed" + IDS_QUEUED "Queued" + IDS_RIPPING "Ripping" + IDS_CANCEL_RIP "Cancel rip?" + IDS_CD_RIP_QUESTION "CD Rip Question" + IDS_INITIALIZING "Initializing..." + IDS_CALCULATING_REPLAY_GAIN "Calculating Replay Gain" + IDS_UNKNOWN_ARTIST "Unknown Artist" + IDS_UNKNOWN_ALBUM "Unknown Album" + IDS_UNKNOWN "Unknown" + IDS_RIP_COMPLETE "Rip Complete" + IDS_RIP_FAILED "Rip Failed" + IDS_X_TRACKS_RIPPED_IN_X + "%d track%s ripped in %d:%02d (%.1fx realtime)\nOutput bitrate: %dkbps, Output size: %.1fMB" +END + +STRINGTABLE +BEGIN + IDS_DONE "Done" + IDS_ELAPSED_X_REMAINING_X_TOTAL_X + "Elapsed: %d:%02d, Remaining: %d:%02d, Total: %d:%02d (%.1fx realtime)\nOutput bitrate: %dkbps, Output size (estimated): %.1fMB" + IDS_X_KBPS_AT_X_REALTIME "%02d%%: %dkbps at %.1fx realtime" + IDS_X_OF_X_ELAPSED_X_REMAINING_X + "%d/%d: Elapsed: %d:%02d, Remaining: %d:%02d, Total: %d:%02d (%.1fx realtime)\nOutput bitrate: %dkbps, Output size (estimated): %.1fMB" + IDS_X_PERCENT_RIPPING_FROM_CD "[%d%%] Ripping from CD..." + IDS_WAITING "Waiting..." + IDS_STAMPED_DISC_OR_RECORDABLE_THAT_HAS_BEEN_RECORDED + "Stamped disc or a recordable disc that has been recorded Disc-At-Once." + IDS_REWRITEABLE_DISC_HAS_DATA_BUT_KEPT_OPEN_FOR_APPEND + "Rewritable disc that contains data but remains open, allowing the appending of additional data." + IDS_REWRITEABLE_DISC_NOT_POSSIBLE_TO_APPEND_DATA + "Rewritable disc not possible to append additional data." + IDS_BLANK_REWRITEABLE_DISC "Blank rewritable disc." + IDS_MEDIA_BLANK_DISC "Blank disc" + IDS_MEDIA_DATA_MODE_1_DAO "Data Mode 1 DAO" + IDS_MEDIA_KODAK_PHOTO_CD "Kodak Photo CD" + IDS_MEDIA_DATA_MULTISESSION_MODE_1_CLOSED + "Data multisession Mode 1 (closed)" + IDS_MEDIA_DATA_MULTISESSION_MODE_2_CLOSED + "Data multisession Mode 2 (closed)" + IDS_MEDIA_DATA_MODE_2_DAO "Data Mode 2 DAO" +END + +STRINGTABLE +BEGIN + IDS_MEDIA_CDRFS "CDRFS" + IDS_MEDIA_PACKET_WRITING "Packet writing" + IDS_MEDIA_DATA_MULTISESSION_MODE_1_OPEN "Data multisession Mode 1 (open)" + IDS_MEDIA_DATA_MULTISESSION_MODE_2_OPEN "Data multisession Mode 2 (open)" + IDS_MEDIA_AUDIO_DAO_SAO_TAO "Audio DAO/SAO/TAO" + IDS_MEDIA_AUDIO_REWRITEABLE_DISC_WITH_SESSION_NOT_CLOSED + "Audio Rewritable disc with session not closed (TAO or SAO)" + IDS_MEDIA_FIRST_TYPE_OF_ENHANCED_CD_ABORTED + "First type of Enhanced CD (aborted)" + IDS_MEDIA_CD_EXTRA "CD Extra" + IDS_MEDIA_AUDIO_TAO_WITH_SESSION_NOT_WRITTEN + "Audio TAO with session not written (in-progress compilation)" + IDS_MEDIA_FIRST_TRACK_DATA_OTHERS_AUDIO "First track data, others audio" + IDS_MEDIA_MIXED_MODE_MADE_TAO "Mixed-mode made TAO" + IDS_MEDIA_KODAK_PORTFOLIO "Kodak Portfolio (as per the Kodak standard)" + IDS_MEDIA_VIDEO_CD "Video CD" + IDS_MEDIA_CDi "CD-i" + IDS_MEDIA_PLAYSTATION_SONY_GAMES "PlayStation (Sony games)" + IDS_MEDIA_OBSOLETE "Obsolete" +END + +STRINGTABLE +BEGIN + IDS_MEDIA_OBSOLETE_FOR_RESTRICTED_OVERWRITE_DVD + "Obsolete for restricted overwrite DVD (DLA DVD-RW)" + IDS_MEDIA_DVDROM_OR_CLOSED_RECORDABLE "DVD-ROM or closed recordable" + IDS_MEDIA_INCREMENTAL_DVD_WITH_APPENDABLE_ZONE + "Incremental DVD with appendable zone (DLA DVD-R and DVD+RW)" + IDS_MEDIA_APPENDABLE_DVD_OF_ANY_TYPE + "Appendable DVD of any type (single border or multiborder)" + IDS_MEDIA_DVDRAM_CARTRIDGE "DVD-RAM cartridge" + IDS_MEDIA_CD_OTHER_TYPE "CD (other type)" + IDS_X_DRIVE_X "%s Drive %c:" + IDS_X_DRIVE_BRACKET_X "%s Drive (%c:)" + IDS_YOU_ARE_CURRENTLY_BURNING_AUDIO_CD_MUST_CANCEL_TO_CLOSE_WINAMP + "You are currently burning Audio CD in drive %c:\nYou must first cancel burning in order to close Winamp." + IDS_NOTIFICATION "Notification" + IDS_RIP_AND_BURN "Rip & Burn" + IDS_CD_RIPPING "CD Ripping" + IDS_CD_BURNER_ON_X "CD Burner on %c:" + IDS_EXAMPLE_RIPPED_FILE_FILENAME "Example ripped file filename:\n" + IDS_EXAMPLE_PLAYLIST_FILENAME "Example playlist filename:\n" + IDS_RIPPED_FILENAME_FORMAT_HELP "Ripped Filename Format Help" +END + +STRINGTABLE +BEGIN + IDS_RIPPPED_PLAYLIST_FORMAT_HELP "Ripped Playlist Filename Format Help" + IDS_RIPPED_PLAYLIST_FORMAT + "<Album> - inserts the album (default capitalization)\r\n<ALBUM> - inserts the album (all uppercase)\r\n<album> - inserts the album (all lowercase)\r\n<Artist> - inserts the album artist (default capitalization)\r\n<ARTIST> - inserts the album artist (all uppercase)\r\n<artist> - inserts the album artist (all lowercase)\r\n<Genre> - inserts the album genre (default capitalization)\r\n<GENRE> - inserts the album genre (all uppercase)\r\n<genre> - inserts the album genre (all lowercase)\r\n<year> - inserts the album year\r\n<disc> - inserts the disc number\r\n<discs> - inserts the total discs number (e.g. CD<disc> of <discs>)" + IDS_RIPPED_FILENAME_FORMAT + "<Album> - inserts the album (default capitalization)\r\n<ALBUM> - inserts the album (all uppercase)\r\n<album> - inserts the album (all lowercase)\r\n<Artist> - inserts the album artist (default capitalization)\r\n<ARTIST> - inserts the album artist (all uppercase)\r\n<artist> - inserts the album artist (all lowercase)\r\n<Genre> - inserts the album genre (default capitalization)\r\n<GENRE> - inserts the album genre (all uppercase)\r\n<genre> - inserts the album genre (all lowercase)\r\n<Title> - inserts the track title (default capitalization)\r\n<TITLE> - inserts the track title (all uppercase)\r\n<title> - inserts the track title (all lowercase)\r\n<Trackartist> - inserts the track artist (default capitalization)\r\n<TRACKARTIST> - inserts the track artist (all uppercase)\r\n<trackartist> - inserts the track artist (all lowercase)\r\n<year> - inserts the album year\r\n#, ##, or ### - inserts the track number, with leading 0s if ## or ###\r\n<disc> - inserts the disc number\r\n<discs> - inserts the total discs number (e.g. CD<disc> of <discs>)" + IDS_CHOOSE_A_FOLDER "Choose a folder" + IDS_TO_EXTRACT_TO_MP3_NEED_TO_PURCHASE_WINAMP_PRO + "In order to extract to MP3, you must purchase Winamp Pro.\nWould you like information on purchasing Winamp Pro?" + IDS_ENCODER "Encoder" + IDS_OUTPUT_FILE_SETTINGS "Output File Settings" + IDS_PLAYLIST_GENERATION "Playlist Generation" + IDS_ERROR_CD_RIP_IN_PROGRESS "Error - CD Rip in progress" + IDS_CD_RIP "CD Rip" + IDS_ERROR_CD_BURN_IN_PROGRESS "Error - CD Burn in progress" + IDS_ERROR_CANNOT_EXTRACT_DATA_CDS "Error - Cannot extract Data CDs" + IDS_NO_TRACKS_TO_RIP "No tracks to rip" + IDS_CD_PLAYBACK_ERROR "CD Playback Error" + IDS_CD_EJECT "CD Eject" + IDS_NO_CD "No CD" +END + +STRINGTABLE +BEGIN + IDS_DATA_TRACK "Data track" + IDS_AUDIO_TRACK "Audio track" + IDS_DISC_READ_ERROR "Unable to read disc info." + IDS_DATA_CD "Data CD" + IDS_DRIVE "drive" + IDS_ARTIST "Artist" + IDS_TRACK "track" + IDS_TRACKS "tracks" + IDS_YES "Yes" + IDS_NO "No" + IDS_SHOW_INFO "Show Info" + IDS_HIDE_INFO "Hide Info" + IDS_READINGDISC "Reading Disc..." + IDS_INFO_RIPPING "Sorry, Information unavailable while ripping cd." + IDS_DVD_DRIVE "DVD Drive" + IDS_CD_DRIVE "CD Drive" +END + +STRINGTABLE +BEGIN + IDS_CD_RECORDER "CD Recorder" + IDS_DATA_DISC "Data Disc" + IDS_BLANK_DISC "Blank Disc" + IDS_DRIVE_CAP "Drive" + IDS_RECORDER_CAP "Recorder" + IDS_CD_AUDIO "Audio CD" + IDS_DISC_BLANK "Blank Disc" + IDS_DISC_DATA "Data Disc" + IDS_CD "CD" + IDS_DVD "DVD" + IDS_CALCULATING "Calculating..." + IDS_ML_VIEW_ARTIST_ALBUM "Artist: %s\nAlbum: %s" + IDS_ML_VIEW_YEAR_GENRE "Year: %s\nGenre: %s" + IDS_RIPPED_PLAYLIST_FORMAT_CAPTION + "You may enter a format string for the playlist of your ripped files.\nIt can contain \\ or / to delimit a path, and the following keywords:" + IDS_RIPPED_FILENAME_FORMAT_CAPTION + "You may enter a filename format string for your ripped files.\nIt can contain \\ or / to delimit a path, and the following keywords:" + IDS_COPY_FILENAME_FORMAT_TITLE "Filename Format Help" +END + +STRINGTABLE +BEGIN + IDS_COPY_FILENAME_FORMAT_CAPTION + "You may enter a format string for your copied files.\nIt can contain \\ or / to delimit a path, and the following keywords:" + IDS_COPY_FILENAME_FORMAT + "<Album> - inserts the album (default capitalization)\r\n<ALBUM> - inserts the album (all uppercase)\r\n<album> - inserts the album (all lowercase)\r\n<Artist> - inserts the album artist (default capitalization)\r\n<ARTIST> - inserts the album artist (all uppercase)\r\n<artist> - inserts the album artist (all lowercase)\r\n<Extension> - inserts file extension (default capitalization)\r\n<EXTENSION> - inserts file extension (all uppercase)\r\n<extension> - inserts file extension (all lowercase)\r\n<Filename> - inserts file name (default capitalization)\r\n<FILENAME> - inserts file name (all uppercase)\r\n<filename> - inserts file name (all lowercase)\r\n<Genre> - inserts the album genre (default capitalization)\r\n<GENRE> - inserts the album genre (all uppercase)\r\n<genre> - inserts the album genre (all lowercase)\r\n<Title> - inserts the track title (default capitalization)\r\n<TITLE> - inserts the track title (all uppercase)\r\n<title> - inserts the track title (all lowercase)\r\n<Trackartist> - inserts the track artist (default capitalization)\r\n<TRACKARTIST> - inserts the track artist (all uppercase)\r\n<trackartist> - inserts the track artist (all lowercase)\r\n<year> - inserts the album year\r\n#, ##, or ### - inserts the track number, with leading 0s if ## or ###" + IDS_OPTIONS_SHOW "Show Options" + IDS_OPTIONS_HIDE "Hide Options" + IDS_COPY_PREP_MESSAGE_SINGLE_FILE + "Are you sure you want to copy '%s' to '%s'?" + IDS_COPY_PREP_MESSAGE_MULTIPLE_FILES + "Are you sure you want to copy these %d files to '%s'?" + IDS_COPY_TASK_PREPARE "Initializing..." + IDS_COPY_TASK_COPY "Copying..." + IDS_COPY_OP_CALCULATESIZE "Calculating total size..." + IDS_COPY_OP_CHECKDESTINATION "Checking destination..." + IDS_COPY_TASK_FINISHED "Completed" + IDS_COPY_ERROR_CAPTION "File Copy Error" + IDS_COPY_ERROR_MESSAGE "Unable to copy files to '%s'.\n\nReason:\t %s.\nCode:\t %d\nDetails:\t %s" + IDS_COPY_ERRMSG_INITIALIZATION_FAILED "Initialization failed" + IDS_COPY_ERRMSG_DIRECTORYCREATE_FAILED "Unable to create directory" + IDS_COPY_ERRMSG_COPYFILE_FAILED "Unable to copy file" +END + +STRINGTABLE +BEGIN + IDS_COPY_ERRMSG_TITLEFORMAT_FAILED "File title formatting failed" + IDS_COPY_ERRMSG_ADDTOMLDB_FAILED + "Unable to add file to local media database" + IDS_COPY_ERRMSG_SETATTRIBUTES_FAILED "Unable to set file attributes" + IDS_COPY_ERRMSG_COPYFILE_USERABORT "User abort" + IDS_COPY_ERRMSG_DELETEFILE_FAILED "Unable to delete file" + IDS_CONFIRM_CREATE_DESTINATION "Confirm Create Destination" + IDS_DESTINATION_NOT_EXIST_FORMAT + "Destination path '%s' does not exist.\nDo you want to create it?" + IDS_CANCEL "Cancel" + IDS_SKIP "Skip" + IDS_OVERWRITE "Overwrite" + IDS_APPLY_TO_ALL_FILES "Apply to all files" + IDS_CONFIRM_FILE_REPLACE "Confirm File Replace" + IDS_FILE_REPLACE_FORMAT "Destination folder '%s' already contains file named '%s'.\n\nWould you like to replace existing file %s with this one? %s" + IDS_CONFIRM_FILE_DELETE "Confirm File Delete" + IDS_READONLY_FILE_DELETE_FORMAT + "The file '%s' is a read-only file.\nAre you sure you want to delete it? " + IDS_SIZE "Size" +END + +STRINGTABLE +BEGIN + IDS_CREATED "Created" + IDS_MODIFIED "Modified" + IDS_UNKNOWN_GENRE "Unknown Genre" + IDS_YOU_ARE_CURRENTLY_COPYING_DATA_CD_MUST_CANCEL_TO_CLOSE_WINAMP + "You are currently copying files from drive %c:\nYou must first cancel copying in order to close Winamp." + IDS_YOU_ARE_CURRENTLY_RIPPING_AUDIO_CD_MUST_CANCEL_TO_CLOSE_WINAMP + "You are currently ripping Audio CD in drive %c:\nYou must first cancel ripping in order to close Winamp." + IDS_ERROR_RIPPING_TRACK "Error ripping track #%d: %s\n\nAborting." + IDS_NO_INFO_AVAILABLE "No information available" +END + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#include "version.rc2" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Src/Plugins/Library/ml_disc/ml_disc.sln b/Src/Plugins/Library/ml_disc/ml_disc.sln new file mode 100644 index 00000000..6fa5a23a --- /dev/null +++ b/Src/Plugins/Library/ml_disc/ml_disc.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29613.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ml_disc", "ml_disc.vcxproj", "{CAEC36CE-5A74-4C31-9956-E2FF8713D26F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CAEC36CE-5A74-4C31-9956-E2FF8713D26F}.Debug|Win32.ActiveCfg = Debug|Win32 + {CAEC36CE-5A74-4C31-9956-E2FF8713D26F}.Debug|Win32.Build.0 = Debug|Win32 + {CAEC36CE-5A74-4C31-9956-E2FF8713D26F}.Debug|x64.ActiveCfg = Debug|x64 + {CAEC36CE-5A74-4C31-9956-E2FF8713D26F}.Debug|x64.Build.0 = Debug|x64 + {CAEC36CE-5A74-4C31-9956-E2FF8713D26F}.Release|Win32.ActiveCfg = Release|Win32 + {CAEC36CE-5A74-4C31-9956-E2FF8713D26F}.Release|Win32.Build.0 = Release|Win32 + {CAEC36CE-5A74-4C31-9956-E2FF8713D26F}.Release|x64.ActiveCfg = Release|x64 + {CAEC36CE-5A74-4C31-9956-E2FF8713D26F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4B5DC2A4-73F3-41B4-A1E4-5F556BDE113D} + EndGlobalSection +EndGlobal diff --git a/Src/Plugins/Library/ml_disc/ml_disc.vcxproj b/Src/Plugins/Library/ml_disc/ml_disc.vcxproj new file mode 100644 index 00000000..a20771ca --- /dev/null +++ b/Src/Plugins/Library/ml_disc/ml_disc.vcxproj @@ -0,0 +1,382 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{CAEC36CE-5A74-4C31-9956-E2FF8713D26F}</ProjectGuid> + <RootNamespace>ml_disc</RootNamespace> + <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + <EmbedManifest>true</EmbedManifest> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <EmbedManifest>true</EmbedManifest> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + <EmbedManifest>true</EmbedManifest> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <EmbedManifest>true</EmbedManifest> + </PropertyGroup> + <PropertyGroup Label="Vcpkg"> + <VcpkgEnableManifest>false</VcpkgEnableManifest> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <InlineFunctionExpansion>Default</InlineFunctionExpansion> + <AdditionalIncludeDirectories>.;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_DEBUG;_WINDOWS;_WIN32_IE=0x0A00;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <SmallerTypeCheck>false</SmallerTypeCheck> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> + <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4838;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;comctl32.lib;winmm.lib;setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + <ResourceCompile> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + <Manifest> + <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile> + </Manifest> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <InlineFunctionExpansion>Default</InlineFunctionExpansion> + <AdditionalIncludeDirectories>.;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN64;_DEBUG;_WINDOWS;_WIN32_IE=0x0A00;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <SmallerTypeCheck>false</SmallerTypeCheck> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> + <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4244;4838;4090;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;comctl32.lib;winmm.lib;setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + <ResourceCompile> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + <Manifest> + <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile> + </Manifest> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>.;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;NDEBUG;_WINDOWS;_WIN32_IE=0x0A00;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4838;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ShowIncludes>false</ShowIncludes> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;comctl32.lib;winmm.lib;setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>false</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <ModuleDefinitionFile> + </ModuleDefinitionFile> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + <ResourceCompile> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + <Manifest> + <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile> + </Manifest> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>.;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN64;NDEBUG;_WINDOWS;_WIN32_IE=0x0A00;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4244;4838;4090;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ShowIncludes>false</ShowIncludes> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;comctl32.lib;winmm.lib;setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>false</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <ModuleDefinitionFile> + </ModuleDefinitionFile> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + <ResourceCompile> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + <Manifest> + <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile> + </Manifest> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\..\General\gen_ml\gaystring.cpp" /> + <ClCompile Include="..\..\General\gen_ml\graphics.cpp" /> + <ClCompile Include="..\..\General\gen_ml\menu.cpp" /> + <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" /> + <ClCompile Include="..\..\..\nu\ChildSizer.cpp" /> + <ClCompile Include="..\..\..\nu\DialogSkinner.cpp" /> + <ClCompile Include="..\..\..\nu\listview.cpp" /> + <ClCompile Include="..\..\..\nu\MediaLibraryInterface.cpp" /> + <ClCompile Include="..\..\..\nu\menushortcuts.cpp" /> + <ClCompile Include="..\..\..\nu\trace.cpp" /> + <ClCompile Include="..\..\..\Winamp\strutil.cpp" /> + <ClCompile Include="cdburn.cpp"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="cdrip.cpp" /> + <ClCompile Include="cmdbar_data.cpp" /> + <ClCompile Include="commandbar.cpp" /> + <ClCompile Include="config.cpp" /> + <ClCompile Include="copyfiles.cpp" /> + <ClCompile Include="copyfiles_post.cpp" /> + <ClCompile Include="copyprep.cpp" /> + <ClCompile Include="copyprogress.cpp" /> + <ClCompile Include="drive.cpp" /> + <ClCompile Include="driveListBox.cpp" /> + <ClCompile Include="drivemngr.cpp" /> + <ClCompile Include="formatfilename.cpp" /> + <ClCompile Include="helpwnd.cpp" /> + <ClCompile Include="infoBox.cpp" /> + <ClCompile Include="M3UWriter.cpp" /> + <ClCompile Include="main.cpp" /> + <ClCompile Include="medium.cpp" /> + <ClCompile Include="PLSWriter.cpp" /> + <ClCompile Include="prefs.cpp" /> + <ClCompile Include="primosdk_helper.cpp" /> + <ClCompile Include="questionwnd.cpp" /> + <ClCompile Include="ReplayGain.cpp" /> + <ClCompile Include="settings.cpp" /> + <ClCompile Include="spti.cpp" /> + <ClCompile Include="view_cdrom.cpp" /> + <ClCompile Include="view_container.cpp" /> + <ClCompile Include="view_data.cpp" /> + <ClCompile Include="view_info.cpp" /> + <ClCompile Include="view_ripburn.cpp" /> + <ClCompile Include="view_wait.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\General\gen_ml\gaystring.h" /> + <ClInclude Include="..\..\General\gen_ml\menu.h" /> + <ClInclude Include="..\..\..\nu\listview.h" /> + <ClInclude Include="..\..\..\Winamp\strutil.h" /> + <ClInclude Include="api__ml_disc.h" /> + <ClInclude Include="commandbar.h" /> + <ClInclude Include="config.h" /> + <ClInclude Include="copyfiles.h" /> + <ClInclude Include="copyinternal.h" /> + <ClInclude Include="drive.h" /> + <ClInclude Include="driveListBox.h" /> + <ClInclude Include="drivemngr.h" /> + <ClInclude Include="infoBox.h" /> + <ClInclude Include="M3UWriter.h" /> + <ClInclude Include="main.h" /> + <ClInclude Include="medium.h" /> + <ClInclude Include="PLSWriter.h" /> + <ClInclude Include="primosdk_helper.h" /> + <ClInclude Include="ReplayGain.h" /> + <ClInclude Include="resource.h" /> + <ClInclude Include="settings.h" /> + <ClInclude Include="spti.h" /> + </ItemGroup> + <ItemGroup> + <Image Include="resources\cdrom_32x32_24.bmp" /> + <Image Include="resources\filecopy.bmp" /> + <Image Include="resources\listbox_back_2x68x24.bmp" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="ml_disc.rc" /> + <ResourceCompile Include="png.rc" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj"> + <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/ml_disc.vcxproj.filters b/Src/Plugins/Library/ml_disc/ml_disc.vcxproj.filters new file mode 100644 index 00000000..0f828c34 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/ml_disc.vcxproj.filters @@ -0,0 +1,250 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="cdrip.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="cdburn.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="cmdbar_data.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="commandbar.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="config.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="copyfiles.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="copyfiles_post.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="copyprep.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="copyprogress.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="drive.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driveListBox.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="drivemngr.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="formatfilename.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="helpwnd.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="infoBox.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="M3UWriter.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="medium.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="PLSWriter.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="prefs.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="primosdk_helper.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="questionwnd.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ReplayGain.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="settings.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="spti.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="view_cdrom.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="view_container.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="view_data.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="view_info.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="view_ripburn.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="view_wait.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\General\gen_ml\graphics.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\ChildSizer.cpp"> + <Filter>Source Files\nu</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\DialogSkinner.cpp"> + <Filter>Source Files\nu</Filter> + </ClCompile> + <ClCompile Include="..\..\General\gen_ml\gaystring.cpp"> + <Filter>Source Files\gen_ml</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\listview.cpp"> + <Filter>Source Files\nu</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\MediaLibraryInterface.cpp"> + <Filter>Source Files\nu</Filter> + </ClCompile> + <ClCompile Include="..\..\General\gen_ml\menu.cpp"> + <Filter>Source Files\gen_ml</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\menushortcuts.cpp"> + <Filter>Source Files\nu</Filter> + </ClCompile> + <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp"> + <Filter>Source Files\gen_ml</Filter> + </ClCompile> + <ClCompile Include="..\..\..\Winamp\strutil.cpp"> + <Filter>Source Files\Winamp</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\trace.cpp"> + <Filter>Source Files\nu</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="api__ml_disc.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="commandbar.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="copyfiles.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="copyinternal.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="drive.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="driveListBox.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="drivemngr.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="infoBox.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="M3UWriter.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="main.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="medium.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="PLSWriter.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="primosdk_helper.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ReplayGain.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="settings.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="spti.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\General\gen_ml\gaystring.h"> + <Filter>Header Files\gen_ml</Filter> + </ClInclude> + <ClInclude Include="..\..\..\nu\listview.h"> + <Filter>Header Files\nu</Filter> + </ClInclude> + <ClInclude Include="..\..\General\gen_ml\menu.h"> + <Filter>Header Files\gen_ml</Filter> + </ClInclude> + <ClInclude Include="..\..\..\Winamp\strutil.h"> + <Filter>Header Files\Winamp</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="png.rc"> + <Filter>Ressource Files</Filter> + </ResourceCompile> + <ResourceCompile Include="ml_disc.rc"> + <Filter>Ressource Files</Filter> + </ResourceCompile> + </ItemGroup> + <ItemGroup> + <Image Include="resources\cdrom_32x32_24.bmp"> + <Filter>Image Files</Filter> + </Image> + <Image Include="resources\filecopy.bmp"> + <Filter>Image Files</Filter> + </Image> + <Image Include="resources\listbox_back_2x68x24.bmp"> + <Filter>Image Files</Filter> + </Image> + </ItemGroup> + <ItemGroup> + <Filter Include="Header Files"> + <UniqueIdentifier>{1b8ee540-fd62-43d4-8cca-be075c8c8d67}</UniqueIdentifier> + </Filter> + <Filter Include="Ressource Files"> + <UniqueIdentifier>{e018c8c5-3a48-41af-bf92-d63db4e43326}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files"> + <UniqueIdentifier>{0b7fb4d3-0bfd-4ef3-90f2-d969de7e4400}</UniqueIdentifier> + </Filter> + <Filter Include="Image Files"> + <UniqueIdentifier>{191771a6-3744-4d06-a476-64f3d85cdd56}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\gen_ml"> + <UniqueIdentifier>{12bdb53c-e56b-4403-bb0c-7fbe8226593c}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\nu"> + <UniqueIdentifier>{64766d69-e8b1-4432-a8f3-d082202e7362}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Winamp"> + <UniqueIdentifier>{bcf8a930-ff77-437f-a229-e985d9675be1}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\nu"> + <UniqueIdentifier>{91f09635-9292-4055-b23d-613bb045199b}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\gen_ml"> + <UniqueIdentifier>{615eddd8-7e7c-4526-a8bf-1afe093a8149}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Winamp"> + <UniqueIdentifier>{ac350456-8c89-462f-b8c1-8868c38dede8}</UniqueIdentifier> + </Filter> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/png.rc b/Src/Plugins/Library/ml_disc/png.rc new file mode 100644 index 00000000..3ae6cdb0 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/png.rc @@ -0,0 +1,45 @@ +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// +// Data +// +IDB_NAVITEM_CDROM RCDATA +".\\resources\\cdrom.png" +IDB_EJECT_NORMAL RCDATA +".\\resources\\eject3.png" +IDB_EJECT_HILITED RCDATA +".\\resources\\eject1.png" +IDB_EJECT_PRESSED RCDATA +".\\resources\\eject2.png" +IDB_EJECT_DISABLED RCDATA +".\\resources\\eject4.png" +IDB_PLAY_NORMAL RCDATA +".\\resources\\play_n.png" +IDB_PLAY_HIGHLIGHTED RCDATA +".\\resources\\play_p.png" +IDB_PLAY_DISABLED RCDATA +".\\resources\\play_d.png" +IDB_PLAY_PRESSED RCDATA +".\\resources\\play_p.png" +IDB_ENQUEUE_NORMAL RCDATA +".\\resources\\enqueue_n.png" +IDB_ENQUEUE_HIGHLIGHTED RCDATA +".\\resources\\enqueue_p.png" +IDB_ENQUEUE_DISABLED RCDATA +".\\resources\\enqueue_d.png" +IDB_ENQUEUE_PRESSED RCDATA +".\\resources\\enqueue_p.png" +IDB_EJECT2_NORMAL RCDATA +".\\resources\\eject_n.png" +IDB_EJECT2_HIGHLIGHTED RCDATA +".\\resources\\eject_p.png" +IDB_EJECT2_DISABLED RCDATA +".\\resources\\eject_d.png" +IDB_EJECT2_PRESSED RCDATA +".\\resources\\eject_p.png" +IDB_FILECOPY RCDATA +".\\resources\\filecopy.png" +IDB_PLAY_MENU RCDATA +".\\resources\\play_menu_16x16.png" +IDB_ENQUEUE_MENU RCDATA +".\\resources\\enqueue_menu_16x16.png" diff --git a/Src/Plugins/Library/ml_disc/prefs.cpp b/Src/Plugins/Library/ml_disc/prefs.cpp new file mode 100644 index 00000000..f145f984 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/prefs.cpp @@ -0,0 +1,351 @@ +#include "main.h" +#include "../nu/AutoWide.h" +#include "./resource.h" +#include "./settings.h" +#include "../Winamp/wa_ipc.h" +#include <strsafe.h> + +static convertConfigStruct m_ccs; +static int m_has_seled; + +static void myEnumProc(intptr_t user_data, const char *desc, int fourcc) +{ + HWND hwndDlg = (HWND) user_data; + if (fourcc == OLD_AAC_CODEC) + return ; + + int a = (INT)SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_ADDSTRING, 0, (LPARAM)(const wchar_t *)AutoWide(desc)); + + SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_SETITEMDATA, (WPARAM)a, fourcc); + + if ( m_ccs.format == fourcc ) + { + m_has_seled = 1; + SendDlgItemMessage( hwndDlg, IDC_ENCFORMAT, CB_SETCURSEL, (WPARAM)a, 0 ); + } +} + +static void doConfigResizeChild(HWND parent, HWND child) +{ + if (child) + { + RECT r; + GetWindowRect(GetDlgItem(parent, IDC_ENC_CONFIG), &r); + ScreenToClient(parent, (LPPOINT)&r); + SetWindowPos(child, 0, r.left, r.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); + ShowWindow(child, SW_SHOWNA); + } +} + +static HWND subWnd; + +static void DisplayFormatExample(HWND hdlg, INT nItemId, BOOL bFile) +{ + BOOL bUpper; + TCHAR szBuffer[MAX_PATH*2] = {0}; + TCHAR szFormat[MAX_PATH] = {0}; + + Settings_ReadString(C_EXTRACT, (bFile) ? EF_TITLEFMT : EF_PLAYLISTFMT, szFormat, ARRAYSIZE(szFormat)); + + WASABI_API_LNGSTRINGW_BUF(((bFile) ? IDS_EXAMPLE_RIPPED_FILE_FILENAME : IDS_EXAMPLE_PLAYLIST_FILENAME), + szBuffer, ARRAYSIZE(szBuffer)); + + FormatFileName(szBuffer, ARRAYSIZE(szBuffer), szFormat, + (bFile) ? 10 : 0xdeadbeef, + TEXT("U2"), TEXT("The Joshua Tree"), + (bFile) ? TEXT("Exit") : NULL, + TEXT("Rock"), + TEXT("1987"), + TEXT("U2"), + NULL, + TEXT("")); + + wchar_t szExtension[32] = {0}; + if (bFile) + { + int c; + Settings_GetInt(C_EXTRACT, EF_FOURCC, &c); + if (c == OLD_AAC_CODEC) Settings_GetDefault(C_EXTRACT, EF_FOURCC, &c); + GetExtensionString(szExtension, ARRAYSIZE(szExtension), c); + + Settings_GetBool(C_EXTRACT, EF_UPPEREXTENSION, &bUpper); + if (bUpper) CharUpper(szExtension); + else CharLower(szExtension); + } + else StringCchCopy(szExtension, ARRAYSIZE(szExtension), TEXT("m3u")); + + StringCchCat(szBuffer, ARRAYSIZE(szBuffer), TEXT(".")); + StringCchCat(szBuffer, ARRAYSIZE(szBuffer), szExtension); + SetDlgItemText(hdlg, nItemId, szBuffer); +} + +static INT_PTR CALLBACK CDPrefs1Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static HWND hActiveHelp = NULL; + + switch (uMsg) + { + case WM_INITDIALOG: + SendDlgItemMessage(hwndDlg, IDC_DESTPATH, EM_SETLIMITTEXT, MAX_PATH, 0); + Settings_SetCheckBox(C_EXTRACT, EF_UPPEREXTENSION, hwndDlg, IDC_UPPERCASEEXT); + Settings_SetDirectoryCtrl(C_EXTRACT, EF_PATH, hwndDlg, IDC_DESTPATH); + Settings_SetDlgItemText(C_EXTRACT, EF_TITLEFMT, hwndDlg, IDC_FILENAMEFMT); + Settings_SetCheckBox(C_EXTRACT, EF_ADDMETADATA, hwndDlg, IDC_TAGFILES); + Settings_SetCheckBox(C_EXTRACT, EF_CALCULATERG, hwndDlg, IDC_AUTO_RG); + Settings_SetCheckBox(C_EXTRACT, EF_USETOTALTRACKS, hwndDlg, IDC_TOTAL_TRACKS); + Settings_SetCheckBox(C_EXTRACT, EF_ADDTOMLDB, hwndDlg, IDC_CHECK_ML); + Settings_SetDlgItemInt(C_EXTRACT, EF_TRACKOFFSET, hwndDlg, IDC_EDIT2); + Settings_SetDlgItemText(C_EXTRACT, EF_COMMENTTEXT, hwndDlg, IDC_EDIT1); + + break; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_DESTPATH: + if (HIWORD(wParam) == EN_CHANGE) Settings_FromDirectoryCtrl(C_EXTRACT, EF_PATH, hwndDlg,IDC_DESTPATH); + break; + case IDC_UPPERCASEEXT: + Settings_FromCheckBox(C_EXTRACT, EF_UPPEREXTENSION, hwndDlg, IDC_UPPERCASEEXT); + DisplayFormatExample(hwndDlg, IDC_FMTOUT, TRUE); + break; + case IDC_FILENAMEFMT: + if (HIWORD(wParam) == EN_CHANGE) + { + Settings_FromDlgItemText(C_EXTRACT, EF_TITLEFMT, hwndDlg, IDC_FILENAMEFMT); + DisplayFormatExample(hwndDlg, IDC_FMTOUT, TRUE); + } + break; + case IDC_BUTTON1: + Settings_BrowseForFolder(C_EXTRACT, EF_PATH, hwndDlg, IDC_DESTPATH); + break; + case IDC_BUTTON2: + if (hActiveHelp) SetWindowPos(hActiveHelp, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + else hActiveHelp = MLDisc_ShowHelp(hwndDlg, MAKEINTRESOURCE(IDS_RIPPED_FILENAME_FORMAT_HELP), + MAKEINTRESOURCE(IDS_RIPPED_FILENAME_FORMAT_CAPTION), MAKEINTRESOURCE(IDS_RIPPED_FILENAME_FORMAT), HF_ALLOWRESIZE); + break; + case IDC_EDIT2: if (EN_CHANGE == HIWORD(wParam)) Settings_FromDlgItemText(C_EXTRACT, EF_TRACKOFFSET, hwndDlg, IDC_EDIT2);break; + case IDC_EDIT1: if (EN_CHANGE == HIWORD(wParam)) Settings_FromDlgItemText(C_EXTRACT, EF_COMMENTTEXT, hwndDlg, IDC_EDIT1); break; + case IDC_AUTO_RG: if (BN_CLICKED == HIWORD(wParam)) Settings_FromCheckBox(C_EXTRACT, EF_CALCULATERG, hwndDlg, IDC_AUTO_RG); break; + case IDC_TOTAL_TRACKS: if (BN_CLICKED == HIWORD(wParam)) Settings_FromCheckBox(C_EXTRACT, EF_USETOTALTRACKS, hwndDlg, IDC_TOTAL_TRACKS); break; + case IDC_TAGFILES: if (BN_CLICKED == HIWORD(wParam)) Settings_FromCheckBox(C_EXTRACT, EF_ADDMETADATA, hwndDlg, IDC_TAGFILES); break; + case IDC_CHECK_ML: if (BN_CLICKED == HIWORD(wParam)) Settings_FromCheckBox(C_EXTRACT, EF_ADDTOMLDB, hwndDlg, IDC_CHECK_ML); break; + + } + break; + case WM_DESTROY: + if (hActiveHelp) DestroyWindow(hActiveHelp); + break; + case WM_PARENTNOTIFY: + if (hActiveHelp && LOWORD(wParam) == WM_DESTROY && hActiveHelp == (HWND)lParam) + hActiveHelp = NULL; + break; + } + return 0; +} + +int getRegVer(); + +static INT_PTR CALLBACK CDPrefs2Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + m_ccs.hwndParent = hwndDlg; + Settings_GetInt(C_EXTRACT, EF_FOURCC, &m_ccs.format); + if (m_ccs.format == OLD_AAC_CODEC) Settings_GetDefault(C_EXTRACT, EF_FOURCC, &m_ccs.format); + + converterEnumFmtStruct enumf = { myEnumProc, (INT)(INT_PTR)hwndDlg }; + m_has_seled = 0; + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&enumf, IPC_CONVERT_CONFIG_ENUMFMTS); + if (!m_has_seled) + { + SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_SETCURSEL, 0, 0); + m_ccs.format = mmioFOURCC('W', 'A', 'V', ' '); + } + + HWND h = (HWND)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM) & m_ccs, IPC_CONVERT_CONFIG); + doConfigResizeChild(hwndDlg, h); + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_ENCFORMAT: + if (HIWORD(wParam) != CBN_SELCHANGE) return 0; + { + int sel = (INT)(INT_PTR)SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETCURSEL, 0, 0); + if (sel != CB_ERR) + { + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&m_ccs, IPC_CONVERT_CONFIG_END); + int last = m_ccs.format; + if (RegisteredEncoder(last) || last == OLD_AAC_CODEC) Settings_GetDefault(C_EXTRACT, EF_FOURCC, &last); + + m_ccs.format = (int)SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETITEMDATA, sel, 0); + Settings_SetInt(C_EXTRACT, EF_FOURCC, m_ccs.format); + + HWND h = (HWND)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM) & m_ccs, IPC_CONVERT_CONFIG); + doConfigResizeChild(hwndDlg, h); + } + } + break; + } + break; + case WM_DESTROY: + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&m_ccs, IPC_CONVERT_CONFIG_END); + break; + } + return 0; +} + + +static INT_PTR CALLBACK CDPrefs4Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static HWND hActiveHelp = NULL; + + switch (uMsg) + { + case WM_INITDIALOG: + Settings_SetDlgItemText(C_EXTRACT, EF_PLAYLISTFMT, hwndDlg, IDC_FILENAMEFMT); + Settings_SetCheckBox(C_EXTRACT, EF_CREATEM3U, hwndDlg, IDC_CHECK1); + Settings_SetCheckBox(C_EXTRACT, EF_USEM3UEXT, hwndDlg, IDC_CHECK3); + Settings_SetCheckBox(C_EXTRACT, EF_CREATEPLS, hwndDlg, IDC_CHECK2); + Settings_SetCheckBox(C_EXTRACT, EF_CREATEMLPL, hwndDlg, IDC_CHECK4); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK3), IsDlgButtonChecked(hwndDlg, IDC_CHECK1)); + break; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_FILENAMEFMT: + if (LOWORD(wParam) != IDC_FILENAMEFMT || HIWORD(wParam) == EN_CHANGE) + { + Settings_FromDlgItemText(C_EXTRACT, EF_PLAYLISTFMT, hwndDlg, IDC_FILENAMEFMT); + DisplayFormatExample(hwndDlg, IDC_FMTOUT, FALSE); + } + return 0; + case IDC_BUTTON2: + if (hActiveHelp) SetWindowPos(hActiveHelp, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + else hActiveHelp = MLDisc_ShowHelp(hwndDlg, MAKEINTRESOURCE(IDS_RIPPPED_PLAYLIST_FORMAT_HELP), + MAKEINTRESOURCE(IDS_RIPPED_PLAYLIST_FORMAT_CAPTION), MAKEINTRESOURCE(IDS_RIPPED_PLAYLIST_FORMAT), HF_ALLOWRESIZE); + break; + case IDC_CHECK1: + if (BN_CLICKED == HIWORD(wParam)) Settings_FromCheckBox(C_EXTRACT, EF_CREATEM3U, hwndDlg, IDC_CHECK1); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK3), IsDlgButtonChecked(hwndDlg, IDC_CHECK1)); + break; + + case IDC_CHECK3: if (BN_CLICKED == HIWORD(wParam)) Settings_FromCheckBox(C_EXTRACT, EF_USEM3UEXT, hwndDlg, IDC_CHECK3); break; + case IDC_CHECK2: if (BN_CLICKED == HIWORD(wParam)) Settings_FromCheckBox(C_EXTRACT, EF_CREATEPLS, hwndDlg, IDC_CHECK2); break; + case IDC_CHECK4: if (BN_CLICKED == HIWORD(wParam)) Settings_FromCheckBox(C_EXTRACT, EF_CREATEMLPL, hwndDlg, IDC_CHECK4); break; + } + break; + + case WM_DESTROY: + if (hActiveHelp) DestroyWindow(hActiveHelp); + break; + case WM_PARENTNOTIFY: + if (hActiveHelp && LOWORD(wParam) == WM_DESTROY && hActiveHelp == (HWND)lParam) + hActiveHelp = NULL; + break; + } + return 0; +} + + +static int has_extract; + +static void _dosetsel(HWND hwndDlg) +{ + HWND tabwnd = GetDlgItem(hwndDlg, IDC_TAB1); + int sel = TabCtrl_GetCurSel(tabwnd); + + if (sel >= 0 && (sel != g_config->ReadInt(L"lastcdprefp", 0) || !subWnd)) + { + g_config->WriteInt(L"lastcdprefp", sel); + if (subWnd) DestroyWindow(subWnd); + subWnd = 0; + + UINT t = 0; + DLGPROC p = NULL; + if (!has_extract && sel) sel++; + switch (sel) + { + case 2: t = IDD_PREFS_CDRIP1; p = CDPrefs1Proc; break; + case 0: t = IDD_PREFS_CDRIP2; p = CDPrefs2Proc; break; + case 3: t = IDD_PREFS_CDRIP4; p = CDPrefs4Proc; break; + case 1: + { + t = 0; + char buf2[512] = {0}; + char buf3[512] = {0}; + StringCchPrintfA(buf3, 512, "cdda_cf_%d", (INT)(INT_PTR)hwndDlg); + getFileInfo("cda://", buf3, buf2, sizeof(buf2)); + subWnd = (HWND)(INT_PTR)atoi(buf2); + } + break; + default: subWnd = 0; t = 0; break; + } + if (t) subWnd = WASABI_API_CREATEDIALOGW(t, hwndDlg, p); + + if (subWnd) + { + RECT r; + GetClientRect(tabwnd, &r); + TabCtrl_AdjustRect(tabwnd, FALSE, &r); + SetWindowPos(subWnd, HWND_TOP, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOACTIVATE); + ShowWindow(subWnd, SW_SHOWNA); + } + + if(!SendMessage(plugin.hwndWinampParent,WM_WA_IPC,IPC_ISWINTHEMEPRESENT,IPC_USE_UXTHEME_FUNC)) + { + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)tabwnd,IPC_USE_UXTHEME_FUNC); + SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)subWnd,IPC_USE_UXTHEME_FUNC); + } + } +} + + +BOOL CALLBACK CDRipPrefsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + TCITEM item; + HWND tabwnd = GetDlgItem(hwndDlg, IDC_TAB1); + item.mask = TCIF_TEXT; + item.pszText = WASABI_API_LNGSTRINGW(IDS_ENCODER); + TabCtrl_InsertItem(tabwnd, 0, &item); + + wchar_t buf2[512] = {0}; + getFileInfoW(L"cda://", L"cdda_config_text", buf2, 512); + + if (buf2[0]) + { + item.pszText = buf2; + TabCtrl_InsertItem(tabwnd, 3, &item); + has_extract = 1; + } + else has_extract = 0; + + item.pszText = WASABI_API_LNGSTRINGW(IDS_OUTPUT_FILE_SETTINGS); + TabCtrl_InsertItem(tabwnd, 1 + has_extract, &item); + item.pszText = WASABI_API_LNGSTRINGW(IDS_PLAYLIST_GENERATION); + TabCtrl_InsertItem(tabwnd, 2 + has_extract, &item); + + TabCtrl_SetCurSel(tabwnd, g_config->ReadInt(L"lastcdprefp", 0)); + _dosetsel(hwndDlg); + } + return 0; + case WM_NOTIFY: + { + LPNMHDR p = (LPNMHDR) lParam; + if (p->idFrom == IDC_TAB1 && p->code == TCN_SELCHANGE) _dosetsel(hwndDlg); + } + return 0; + case WM_DESTROY: + subWnd = NULL; + return 0; + } + return 0; +} + diff --git a/Src/Plugins/Library/ml_disc/primosdk_helper.cpp b/Src/Plugins/Library/ml_disc/primosdk_helper.cpp new file mode 100644 index 00000000..60b32ff2 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/primosdk_helper.cpp @@ -0,0 +1,109 @@ +#include "./primosdk_helper.h" +//#include "../primo/obj_primo.h" +#include "api__ml_disc.h" +#include <api/service/waservicefactory.h> + +typedef struct _PRIMOSDK_INSTANCE +{ +// obj_primo *primo; + BOOL bLoadFailed; + LONG uRef; +} PRIMOSDK_INSTANCE; + +static PRIMOSDK_INSTANCE sdk = {/*NULL,*/ FALSE, 0, }; + +BOOL PrimoSDKHelper_IsInitialized(void) +{ + return (0 != sdk.uRef); +} + +BOOL PrimoSDKHelper_IsLoaded(void) +{ + /*char t[64] = {0}; + wsprintfA(t,"%d %d %d\n%d",sdk.bLoadFailed, sdk.primo, sdk.uRef, !(!sdk.uRef || !sdk.primo)); + MessageBoxA(0,t,0,0);*/ + return !(!sdk.uRef /*|| !sdk.primo*/);//(sdk.bLoadFailed==FALSE); +} + +LONG PrimoSDKHelper_Initialize(void) +{ + return 0; +#if 0 + if (sdk.bLoadFailed) return 0; + + if (!sdk.uRef) + { + BOOL bFailed = TRUE; + waServiceFactory *sf = plugin.service->service_getServiceByGuid(obj_primo::getServiceGuid()); + if (sf) sdk.primo = reinterpret_cast<obj_primo *>(sf->getInterface()); + if (sdk.primo) + bFailed = FALSE; + + sdk.bLoadFailed += bFailed; + } + InterlockedIncrement(&sdk.uRef); + + return sdk.uRef; +#endif +} + +LONG PrimoSDKHelper_Uninitialize(void) +{ + return 0; +#if 0 + if (sdk.uRef && 0 == InterlockedDecrement(&sdk.uRef)) + { + if (sdk.primo) + { + waServiceFactory *sf = plugin.service->service_getServiceByGuid(obj_primo::getServiceGuid()); + if (sf) sf->releaseInterface(sdk.primo); + sdk.primo = 0; + } + } + return sdk.uRef; +#endif +} + +DWORD PrimoSDKHelper_UnitInfo(PDWORD pdwUnit, PDWORD pdwType, PBYTE szDescr, PDWORD pdwReady) +{ + return PRIMOSDK_CMDSEQUENCE; +#if 0 + if (!sdk.uRef) return PRIMOSDK_CMDSEQUENCE; + if (!sdk.primo) return PRIMOSDK_CMDSEQUENCE; + + return sdk.primo->UnitInfo(pdwUnit, pdwType, szDescr, pdwReady); +#endif +} + +DWORD PrimoSDKHelper_UnitInfo2(PDWORD pdwUnit, PDWORD pdwTypes, PDWORD pdwClass, PDWORD pdwBusType, PDWORD pdwRFU) +{ +return PRIMOSDK_CMDSEQUENCE; +#if 0 + if (!sdk.uRef) return PRIMOSDK_CMDSEQUENCE; + if (!sdk.primo) return PRIMOSDK_CMDSEQUENCE; + + return sdk.primo->UnitInfo2(pdwUnit, pdwTypes, pdwClass, pdwBusType, pdwRFU); +#endif +} + +DWORD PrimoSDKHelper_DiscInfoEx(PDWORD pdwUnit, DWORD dwFlags, PDWORD pdwMediumType, PDWORD pdwMediumFormat, PDWORD pdwErasable, PDWORD pdwTracks, PDWORD pdwUsed, PDWORD pdwFree) +{ +#if 0 + if (!sdk.uRef) return PRIMOSDK_CMDSEQUENCE; + if (!sdk.primo) return PRIMOSDK_CMDSEQUENCE; + + return sdk.primo->DiscInfoEx(pdwUnit, dwFlags, pdwMediumType, pdwMediumFormat, pdwErasable, pdwTracks, pdwUsed, pdwFree); +#endif + return PRIMOSDK_CMDSEQUENCE; +} + +DWORD PrimoSDKHelper_DiscInfo2(PDWORD pdwUnit, PDWORD pdwMedium, PDWORD pdwProtectedDVD, PDWORD pdwFlags, PDWORD pdwMediumEx, PDWORD pdwRFU3) +{ + return PRIMOSDK_CMDSEQUENCE; +#if 0 + if (!sdk.uRef) return PRIMOSDK_CMDSEQUENCE; + if (!sdk.primo) return PRIMOSDK_CMDSEQUENCE; + + return sdk.primo->DiscInfo2(pdwUnit, pdwMedium, pdwProtectedDVD, pdwFlags, pdwMediumEx, pdwRFU3); +#endif +} diff --git a/Src/Plugins/Library/ml_disc/primosdk_helper.h b/Src/Plugins/Library/ml_disc/primosdk_helper.h new file mode 100644 index 00000000..04078bfd --- /dev/null +++ b/Src/Plugins/Library/ml_disc/primosdk_helper.h @@ -0,0 +1,31 @@ +#ifndef NULLOSFT_MLDISC_PRIMOSDK_HELPER_HEADER +#define NULLOSFT_MLDISC_PRIMOSDK_HELPER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> +//#include <primosdk.h> +#define PRIMOSDK_CMDSEQUENCE ((DWORD)0xFFFFFFFF) +#define PRIMOSDK_OK 0 +#define PRIMOSDK_PACKETWRITTEN 0 +// !!!! Not thread safe !!!! + +#define DEFAULT_HANDLE ((DWORD)0xFFFFFFFF) + +// Initialization +LONG PrimoSDKHelper_Initialize(void); +LONG PrimoSDKHelper_Uninitialize(void); +BOOL PrimoSDKHelper_IsInitialized(void); +BOOL PrimoSDKHelper_IsLoaded(void); + +// Drive Info (You can use DEFAULT_HANDLE) +DWORD PrimoSDKHelper_UnitInfo(PDWORD pdwUnit, PDWORD pdwType, PBYTE szDescr, PDWORD pdwReady); +DWORD PrimoSDKHelper_UnitInfo2(PDWORD pdwUnit, PDWORD pdwTypes, PDWORD pdwClass, PDWORD pdwBusType, PDWORD pdwRFU); + +// Medium Info (You can use DEFAULT_HANDLE) +DWORD PrimoSDKHelper_DiscInfoEx(PDWORD pdwUnit, DWORD dwFlags, PDWORD pdwMediumType, PDWORD pdwMediumFormat, PDWORD pdwErasable, PDWORD pdwTracks, PDWORD pdwUsed, PDWORD pdwFree); +DWORD PrimoSDKHelper_DiscInfo2(PDWORD pdwUnit, PDWORD pdwMedium, PDWORD pdwProtectedDVD, PDWORD pdwFlags, PDWORD pdwMediumEx, PDWORD pdwRFU3); + +#endif // NULLOSFT_MLDISC_PRIMOSDK_HELPER_HEADER diff --git a/Src/Plugins/Library/ml_disc/questionwnd.cpp b/Src/Plugins/Library/ml_disc/questionwnd.cpp new file mode 100644 index 00000000..66071eea --- /dev/null +++ b/Src/Plugins/Library/ml_disc/questionwnd.cpp @@ -0,0 +1,279 @@ +#include "main.h" +#include "./copyfiles.h" +#include "./copyinternal.h" +#include "./resource.h" +#include "../nu/trace.h" +#include <shlwapi.h> +#include <strsafe.h> + + +#define QUESTIONBOX_PROP TEXT("QUESTIONBOX") +#define GetQuestionBox(__hdlg) ((QUESTIONBOX*)GetProp((__hdlg), QUESTIONBOX_PROP)) + + +#define GetResolvedString(__pszText, __pszBuffer, __chhBufferMax)\ + (IS_INTRESOURCE(__pszText) ? WASABI_API_LNGSTRINGW_BUF((UINT)(UINT_PTR)(__pszText), (__pszBuffer), (__chhBufferMax)) : (__pszText)) + +static INT_PTR CALLBACK CopyQuestion_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +INT_PTR MLDisc_ShowQuestionBox(QUESTIONBOX *pQuestionBox) +{ + if (!pQuestionBox) return IDCANCEL; + return WASABI_API_DIALOGBOXPARAMW(IDD_FILECOPY_QUESTION, pQuestionBox->hParent, CopyQuestion_DialogProc, (LPARAM)pQuestionBox); +} + +static BOOL FindPrefferedSizeEx(HDC hdc, LPCTSTR pszText, LPCTSTR pszNewLine, SIZE *pSize) +{ + if (!pSize) return FALSE; + pSize->cx = 0; pSize->cy = 0; + if (!hdc || !pszText || !pszNewLine) return FALSE; + LPCTSTR pszBlock = pszText; + LPCTSTR pszCursor = pszBlock; + INT cchSep = lstrlenW(pszNewLine); + INT matched = 0; + for(;;) + { + if (*pszCursor) + { + if (*pszCursor == pszNewLine[matched]) matched++; + else matched = 0; + pszCursor++; + } + if (matched == cchSep || TEXT('\0') == *pszCursor) + { + SIZE sz; + + INT l = (INT)(size_t)((pszCursor - pszBlock) - matched); + if (l > 0) + { + if (!GetTextExtentPoint32(hdc, pszBlock, l, &sz)) return FALSE; + } + else + { + if (!GetTextExtentPoint32(hdc, TEXT("\n"), 1, &sz)) return FALSE; + sz.cx = 0; + } + + if (pSize->cx < sz.cx) pSize->cx= sz.cx; + pSize->cy += sz.cy; + + if (TEXT('\0') == *pszCursor) break; + else + { + matched = 0; + pszBlock = pszCursor; + } + } + } + return TRUE; +} + +static BOOL FindPrefferedSize(HWND hwnd, LPCTSTR pszText, LPCTSTR pszNewLine, SIZE *pSize) +{ + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_PARENTCLIP); + if (!hdc) return FALSE; + HFONT hf, hfo; + hf = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L); + if (NULL == hf) hf = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + hfo = (NULL != hf) ? (HFONT)SelectObject(hdc, hf) : NULL; + + BOOL br = FindPrefferedSizeEx(hdc, pszText, pszNewLine, pSize); + + if (hfo) SelectObject(hdc, hfo); + ReleaseDC(hwnd, hdc); + + return br; +} + +static INT_PTR CopyQuestion_OnInitDialog(HWND hdlg, HWND hFocus, QUESTIONBOX *pqb) +{ + if (!pqb) return FALSE; + SetProp(hdlg, QUESTIONBOX_PROP, pqb); + + HWND hctrl; + TCHAR szBuffer[2048] = {0}; + LONG messageLeft = 0; + + if (NULL != pqb->pszTitle) SetWindowText(hdlg, GetResolvedString(pqb->pszTitle, szBuffer, ARRAYSIZE(szBuffer))); + + if (NULL != pqb->pszBtnOkText) SetDlgItemText(hdlg, IDOK, GetResolvedString(pqb->pszBtnOkText, szBuffer, ARRAYSIZE(szBuffer))); + if (NULL != pqb->pszBtnCancelText) SetDlgItemText(hdlg, IDCANCEL, GetResolvedString(pqb->pszBtnCancelText, szBuffer, ARRAYSIZE(szBuffer))); + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_BTN_EXTRA1))) + { + ShowWindow(hctrl, (QBF_SHOW_EXTRA_BUTTON & pqb->uFlags) ? SW_SHOWNA : SW_HIDE); + if (NULL != pqb->pszBtnExtraText) SetWindowText(hctrl, GetResolvedString(pqb->pszBtnExtraText, szBuffer, ARRAYSIZE(szBuffer))); + } + + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_PIC_ICON))) + { + HICON hIcon = NULL; + if (NULL != pqb->pszIcon) + { + hIcon = LoadIcon(WASABI_API_LNG_HINST, pqb->pszIcon); + if (NULL == hIcon) hIcon = LoadIcon(WASABI_API_ORIG_HINST, pqb->pszIcon); + if (NULL == hIcon) hIcon = LoadIcon(NULL, pqb->pszIcon); + } + SendMessage(hctrl, STM_SETICON, (WPARAM)hIcon, 0L); + ShowWindow(hctrl, (hIcon) ? SW_SHOWNA : SW_HIDE); + RECT rw; + GetWindowRect(hctrl, &rw); + MapWindowPoints(HWND_DESKTOP, hdlg, (POINT*)&rw, 2); + messageLeft = (hIcon) ? (rw.right + 24) : rw.left; + } + + INT shiftRight = 0, shiftBottom = 0; + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_LBL_MESSAGE))) + { + RECT rw; + SIZE textSize = { 0, 0 }; + LPCTSTR pszText = (NULL != pqb->pszMessage) ? GetResolvedString(pqb->pszMessage, szBuffer, ARRAYSIZE(szBuffer)) : NULL; + if (pszText) + { + FindPrefferedSize(hctrl, pszText, TEXT("\n"), &textSize); + textSize.cx += 8; textSize.cy += 4; + } + SetWindowText(hctrl, pszText); + GetWindowRect(hctrl, &rw); + MapWindowPoints(HWND_DESKTOP, hdlg, (POINT*)&rw, 2); + rw.left = messageLeft; + shiftRight = (rw.left + textSize.cx) - rw.right; + if (shiftRight < 0) shiftRight = 0; + shiftBottom = textSize.cy - (rw.bottom - rw.top); + if (shiftBottom < 0) shiftBottom = 0; + SetWindowPos(hctrl, NULL, rw.left, rw.top, (rw.right - rw.left) + shiftRight, (rw.bottom - rw.top) + shiftBottom, SWP_NOACTIVATE | SWP_NOZORDER); + } + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_CHECKBOX1))) + { + + if (NULL != pqb->pszCheckboxText) SetWindowText(hctrl, GetResolvedString(pqb->pszCheckboxText, szBuffer, ARRAYSIZE(szBuffer))); + SendMessage(hctrl, BM_SETCHECK, (pqb->checkboxChecked) ? BST_CHECKED : BST_UNCHECKED, 0L); + + RECT rw; + GetWindowRect(hctrl, &rw); + + if (0 == (QBF_SHOW_CHECKBOX & pqb->uFlags)) + { + shiftBottom -= (rw.bottom - rw.top); + ShowWindow(hctrl, SW_HIDE); + } + else if (shiftRight || shiftBottom) + { + MapWindowPoints(HWND_DESKTOP, hdlg, (POINT*)&rw, 2); + SetWindowPos(hctrl, NULL, rw.left, rw.top + shiftBottom, + (rw.right - rw.bottom) + shiftRight, (rw.bottom - rw.top), SWP_NOACTIVATE | SWP_NOZORDER); + ShowWindow(hctrl, SW_SHOWNA); + } + } + + if (shiftRight || shiftBottom) + { + RECT rw; + INT idList[] = {IDC_BTN_EXTRA1, IDOK, IDCANCEL, }; + for (int i = 0; i < ARRAYSIZE(idList); i++) + { + if (NULL != (hctrl = GetDlgItem(hdlg, idList[i]))) + { + GetWindowRect(hctrl, &rw); + MapWindowPoints(HWND_DESKTOP, hdlg, (POINT*)&rw, 2); + SetWindowPos(hctrl, NULL, rw.left + shiftRight, rw.top + shiftBottom, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + } + } + + } + + HWND hParent = GetParent(hdlg); + if (hParent) + { + RECT rw, rc; + GetClientRect(hParent, &rc); + GetWindowRect(hdlg, &rw); + rw.right += shiftRight; + rw.bottom += shiftBottom; + + SetWindowPos(hdlg, NULL, + rw.left + ((rc.right - rc.left) - (rw.right - rw.left))/2, + rw.top + ((rc.bottom - rc.top) - (rw.bottom - rw.top))/2, + rw.right - rw.left, rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOZORDER); + } + + SendMessage(hdlg, DM_REPOSITION, 0, 0L); + return FALSE; +} + +static void CopyQuestion_OnDestroy(HWND hdlg) +{ + QUESTIONBOX *pqb = GetQuestionBox(hdlg); + if (pqb) + { + pqb->checkboxChecked = (BST_CHECKED == IsDlgButtonChecked(hdlg, IDC_CHECKBOX1)); + } + RemoveProp(hdlg, QUESTIONBOX_PROP); +} + +static void CopyQuestion_OnCommand(HWND hdlg, INT ctrlId, INT eventId, HWND hctrl) +{ + switch(ctrlId) + { + case IDOK: + case IDCANCEL: + EndDialog(hdlg, ctrlId); + break; + case IDC_BTN_EXTRA1: + if (BN_CLICKED == eventId) EndDialog(hdlg, ctrlId); + break; + } +} +#define IDT_POSTSHOW 1985 +#define DELAY_POSTSHOW 0 + +static void CALLBACK CopyQuestion_OnPostShowElapsed(HWND hdlg, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + QUESTIONBOX *pqb = GetQuestionBox(hdlg); + KillTimer(hdlg, idEvent); + if (!pqb) return; + + if (QBF_FLASH & pqb->uFlags) + { + FLASHWINFO flash = { sizeof(FLASHWINFO), }; + flash.hwnd = hdlg; + flash.dwFlags = FLASHW_ALL; + flash.uCount = 2; + flash.dwTimeout = 300; + FlashWindowEx(&flash); + } + + if (QBF_BEEP & pqb->uFlags) MessageBeep(pqb->uBeepType); + + if ((QBF_SETFOREGROUND | QBF_TOPMOST) & pqb->uFlags) + { + SetForegroundWindow(hdlg); + SetWindowPos(hdlg, (QBF_SETFOREGROUND & pqb->uFlags) ? HWND_TOP : HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + } + + + + + +} +static void CopyQuestion_OnShowWindow(HWND hdlg, BOOL bShow, UINT nStatus) +{ + if (bShow) + { + SetTimer(hdlg, IDT_POSTSHOW, DELAY_POSTSHOW, CopyQuestion_OnPostShowElapsed); + } +} + +static INT_PTR CALLBACK CopyQuestion_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return CopyQuestion_OnInitDialog(hdlg, (HWND)wParam, (QUESTIONBOX*)lParam); + case WM_DESTROY: CopyQuestion_OnDestroy(hdlg); break; + case WM_COMMAND: CopyQuestion_OnCommand(hdlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break; + case WM_SHOWWINDOW: CopyQuestion_OnShowWindow(hdlg, (BOOL)wParam, (UINT)lParam); break; + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/resource.h b/Src/Plugins/Library/ml_disc/resource.h new file mode 100644 index 00000000..60dec117 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resource.h @@ -0,0 +1,455 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ml_disc.rc +// +#define IDS_ERROR_WRITING_TEMP_BURN_LIST 1 +#define IDS_ERROR 2 +#define IDS_BURN_X_TRACKX_ON_X 3 +#define IDS_X_OF_X_SECTORS_FREE 4 +#define IDS_GET_PRO_FOR_BURN_HIGHER_THAN_2X 5 +// #define IDS_WINAMP_PRO_FEATURE 6 +#define IDS_NEED_TO_ADD_SOME_TRACKS_TO_BURN 7 +#define IDS_TOTAL_LENGTH_IS_BIGGER_THAN_MEDIA_CAPACITY 8 +#define IDS_BURNING 9 +#define IDS_CANCEL_BURN 10 +#define IDS_NO_BLANK_CDR_IN_DRIVE 11 +#define IDS_X_CAPACITY_DETAILS 12 +#define IDS_USED_X_X_TRACKS 13 +#define IDS_AVAILABLE_X_X 14 +#define IDS_X_OVER_CAPACITY_REMOVE_X_TRACKS 15 +#define IDS_FILE_X_CANNOT_BE_BURNED_REASON_NOT_FOUND 16 +#define IDS_FILE_X_CANNOT_BE_BURNED_REASON_FILETYPE_NOT_REGISTERED 17 +#define IDS_FILE_X_CANNOT_BE_BURNED_REASON_X 18 +#define IDS_VIDEO_FILES_CANNOT_BE_BURNED 19 +#define IDS_NOT_AN_AUDIO_FILE 20 +#define IDS_FILE_CANNOT_BE_BURNED 21 +#define IDS_TRACK_NUMBER 22 +#define IDS_TITLE 23 +#define IDS_LENGTH 24 +#define IDS_STATUS 25 +#define IDS_CANCELLING 26 +#define IDS_BURNING_AUDIO_CANCELLING 27 +#define IDS_BURNING_AUDIO_FINISHING 28 +#define IDS_BURNING_AUDIO_DATA_PREP_FINISHED 29 +#define IDS_BURNING_AUDIO_VERIFYING_FILES 30 +#define IDS_BURNING_AUDIO_VERIFICATION_COMPLETED 31 +#define IDS_OPENING_DISC_WRITING_LEAD_IN 32 +#define IDS_CLOSING_DISC_WRITING_LEAD_OUT 33 +#define IDS_BURNING_AUDIO_CURRENT_OPERATION 34 +#define IDS_BURNING_AUDIO_CD_PREP_DATA 35 +#define IDS_BURNING_AUDIO_BURNING_DATA 36 +#define IDS_CLOSE 37 +#define IDS_AUDIO_CD_BURNED_SUCCESSFULLY 38 +#define IDS_BURN_ABORTED_BY_USER 39 +#define IDS_BURNING_FAILED 40 +#define IDS_BURNING_COMPLETED_STATUS_X 41 +#define IDS_ALL_FILES 42 +#define IDS_ADD_FILES_TO_BURNING_LIST 43 +#define IDS_CHOOSE_A_FOLDER_TO_ADD_TO_BURNING_LIST 44 +#define IDS_SURE_YOU_WANT_TO_CLEAR_BURNING_LIST 45 +#define IDS_CONFIRMATION 46 +#define IDS_BURNING_ 47 +#define IDS_PREPARING 48 +#define IDS_FINISHED 49 +#define IDS_PREPARED 50 +#define IDS_SKIPPED 51 +#define IDS_SCHEDULED 52 +#define IDS_CHECKING_LICENSE 53 +#define IDS_LICENSED 54 +#define IDS_CANCELLED 55 +#define IDS_FAILED 56 +#define IDS_BAD_FILENAME 57 +#define IDS_UNABLE_TO_OPEN_FILE 58 +#define IDS_CACHE_WRITE_FAILED 59 +#define IDS_UNABLE_TO_FIND_DECODER 60 +#define IDS_CANNOT_ADD_TO_THE_DISC 61 +#define IDS_CACHE_READ_FAILED 62 +#define IDS_UNKNOWN_ERROR 63 +#define IDS_ADDING_TRACKS_TO_BURNER_TOTAL_LENGTH_X 64 +#define IDS_PLEASE_INSERT_BLANK_RECORDABLE_CD 65 +#define IDS_COMPLETED 66 +#define IDS_QUEUED 67 +#define IDS_RIPPING 68 +#define IDS_CANCEL_RIP 69 +#define IDS_CD_RIP_QUESTION 70 +#define IDS_INITIALIZING 71 +#define IDS_CALCULATING_REPLAY_GAIN 72 +#define IDS_UNKNOWN_ARTIST 73 +#define IDS_UNKNOWN_ALBUM 74 +#define IDS_UNKNOWN 75 +#define IDS_RIP_COMPLETE 77 +#define IDS_RIP_FAILED 78 +#define IDS_X_TRACKS_RIPPED_IN_X 79 +#define IDS_DONE 80 +#define IDS_ELAPSED_X_REMAINING_X_TOTAL_X 81 +#define IDS_X_KBPS_AT_X_REALTIME 82 +#define IDS_X_OF_X_ELAPSED_X_REMAINING_X 83 +#define IDS_X_PERCENT_RIPPING_FROM_CD 84 +#define IDS_WAITING 85 +#define IDS_STAMPED_DISC_OR_RECORDABLE_THAT_HAS_BEEN_RECORDED 86 +#define IDS_REWRITEABLE_DISC_HAS_DATA_BUT_KEPT_OPEN_FOR_APPEND 87 +#define IDS_REWRITEABLE_DISC_NOT_POSSIBLE_TO_APPEND_DATA 88 +#define IDS_BLANK_REWRITEABLE_DISC 89 +#define IDS_MEDIA_BLANK_DISC 90 +#define IDS_MEDIA_DATA_MODE_1_DAO 91 +#define IDS_MEDIA_KODAK_PHOTO_CD 92 +#define IDS_MEDIA_DATA_MULTISESSION_MODE_1_CLOSED 93 +#define IDS_MEDIA_DATA_MULTISESSION_MODE_2_CLOSED 94 +#define IDS_MEDIA_DATA_MODE_2_DAO 95 +#define IDS_MEDIA_CDRFS 96 +#define IDS_MEDIA_PACKET_WRITING 97 +#define IDS_MEDIA_DATA_MULTISESSION_MODE_1_OPEN 98 +#define IDS_MEDIA_DATA_MULTISESSION_MODE_2_OPEN 99 +#define IDS_MEDIA_AUDIO_DAO_SAO_TAO 100 +#define IDS_MEDIA_AUDIO_REWRITEABLE_DISC_WITH_SESSION_NOT_CLOSED 101 +#define IDS_MEDIA_FIRST_TYPE_OF_ENHANCED_CD_ABORTED 102 +#define IDS_MEDIA_CD_EXTRA 103 +#define IDS_MEDIA_AUDIO_TAO_WITH_SESSION_NOT_WRITTEN 104 +#define IDS_MEDIA_FIRST_TRACK_DATA_OTHERS_AUDIO 105 +#define IDS_MEDIA_MIXED_MODE_MADE_TAO 106 +#define IDR_CONTEXTMENUS 107 +#define IDS_MEDIA_KODAK_PORTFOLIO 107 +#define IDS_MEDIA_VIDEO_CD 108 +#define IDS_MEDIA_CDi 109 +#define IDD_VIEW_CONTAINER 109 +#define IDD_VIEW_CDROM 110 +#define IDS_MEDIA_PLAYSTATION_SONY_GAMES 110 +#define IDD_VIEW_CDROM1 110 +#define IDD_PREFSCDRIPFR 111 +#define IDS_MEDIA_OBSOLETE 111 +#define IDD_PREFS_CDRIP1 112 +#define IDS_MEDIA_OBSOLETE_FOR_RESTRICTED_OVERWRITE_DVD 112 +#define IDD_PREFS_CDRIP2 113 +#define IDS_MEDIA_DVDROM_OR_CLOSED_RECORDABLE 113 +#define IDD_PREFS_CDRIP4 114 +#define IDS_MEDIA_INCREMENTAL_DVD_WITH_APPENDABLE_ZONE 114 +#define IDD_VIEW_CDROM_EXTRACT 115 +#define IDS_MEDIA_APPENDABLE_DVD_OF_ANY_TYPE 115 +#define IDD_VIEW_CDROM_EX2 116 +#define IDS_MEDIA_DVDRAM_CARTRIDGE 116 +#define IDD_VIEW_CDROM_BURN 117 +#define IDS_MEDIA_CD_OTHER_TYPE 117 +#define IDD_BURN_ADD_STATUS 118 +#define IDS_X_DRIVE_X 118 +#define IDD_BURN 119 +#define IDS_X_DRIVE_BRACKET_X 119 +#define IDD_WAITFORCDR 120 +#define IDS_YOU_ARE_CURRENTLY_BURNING_AUDIO_CD_MUST_CANCEL_TO_CLOSE_WINAMP 120 +#define IDD_UPSELL_RIPPING 121 +#define IDS_NOTIFICATION 121 +#define IDD_NOBURN 122 +#define IDS_RIP_AND_BURN 122 +#define IDD_VIEW_RIPBURN 123 +#define IDS_CD_RIPPING 123 +#define IDS_CD_BURNER_ON_X 124 +#define IDD_VIEW_WAIT 124 +#define IDS_EXAMPLE_RIPPED_FILE_FILENAME 125 +#define IDD_VIEW_INFO 125 +#define IDS_EXAMPLE_PLAYLIST_FILENAME 126 +#define IDD_DIALOG1 126 +#define IDD_VIEW_CDROM_DATA 126 +#define IDS_RIPPED_FILENAME_FORMAT_HELP 127 +#define IDS_RIPPPED_PLAYLIST_FORMAT_HELP 128 +#define IDD_COMMANDBAR_DATA 128 +#define IDS_RIPPED_PLAYLIST_FORMAT 129 +#define IDS_RIPPED_FILENAME_FORMAT 130 +#define IDS_CHOOSE_A_FOLDER 131 +#define IDR_DATAVIEW_ACCELERATOR 131 +#define IDR_ACCELERATOR_VIEW 131 +#define IDS_TO_EXTRACT_TO_MP3_NEED_TO_PURCHASE_WINAMP_PRO 132 +#define IDD_FILECOPY_PREPARE 132 +#define IDS_ENCODER 133 +#define IDD_FILECOPY_PROGRESS 133 +#define IDS_OUTPUT_FILE_SETTINGS 134 +#define IDS_PLAYLIST_GENERATION 135 +#define IDS_ERROR_CD_RIP_IN_PROGRESS 136 +#define IDB_BITMAP1 136 +#define IDB_FILECOPY 136 +#define IDS_CD_RIP 137 +#define IDD_DLG_SIMPLEHELP 137 +#define IDD_SIMPLEHELP 137 +#define IDS_ERROR_CD_BURN_IN_PROGRESS 138 +#define IDD_FILECOPY_QUESTION 138 +#define IDS_ERROR_CANNOT_EXTRACT_DATA_CDS 139 +#define IDS_NO_TRACKS_TO_RIP 140 +#define IDS_CD_PLAYBACK_ERROR 141 +#define IDS_CD_EJECT 142 +#define IDS_NO_CD 143 +#define IDS_DATA_TRACK 144 +#define IDS_AUDIO_TRACK 145 +#define IDS_DISC_READ_ERROR 146 +#define IDS_DATA_CD 147 +#define IDS_DRIVE 148 +#define IDS_ARTIST 149 +#define IDS_TRACK 150 +#define IDS_TRACKS 151 +#define IDS_YES 152 +#define IDS_NO 153 +#define IDS_SHOW_INFO 154 +#define IDS_HIDE_INFO 155 +#define IDS_READINGDISC 156 +#define IDS_INFO_RIPPING 157 +#define IDS_DVD_DRIVE 158 +#define IDS_CD_DRIVE 159 +#define IDS_CD_RECORDER 160 +#define IDS_DATA_DISC 161 +#define IDS_STRING162 162 +#define IDS_BLANK_DISC 162 +#define IDS_DRIVE_CAP 163 +#define IDS_RECORDER_CAP 164 +#define IDS_CD_AUDIO 165 +#define IDS_DISC_BLANK 166 +#define IDS_DISC_DATA 167 +#define IDS_CD 168 +#define IDS_DVD 169 +#define IDS_CALCULATING 170 +#define IDS_ML_VIEW_ARTIST_ALBUM 171 +#define IDS_ML_VIEW_YEAR_GENRE 172 +#define IDS_RIPPED_PLAYLIST_FORMAT_CAPTION 173 +#define IDS_RIPPED_FILENAME_FORMAT_CAPTION 174 +#define IDS_COPY_FILENAME_FORMAT_TITLE 175 +#define IDS_COPY_FILENAME_FORMAT_CAPTION 176 +#define IDS_COPY_FILENAME_FORMAT 177 +#define IDS_OPTIONS_SHOW 178 +#define IDS_OPTIONS_HIDE 179 +#define IDS_EXAMPLE 180 +#define IDS_COPY_PREP_MESSAGE_SINGLE_FILE 180 +#define IDS_COPY_PREP_MESSAGE_MULTIPLE_FILES 181 +#define IDS_COPY_TASK_PREPARE 182 +#define IDS_COPY_TASK_COPY 183 +#define IDS_COPY_OP_CALCULATESIZE 184 +#define IDS_COPY_OP_CHECKDESTINATION 185 +#define IDS_COPY_TASK_FINISHED 186 +#define IDS_COPY_ERROR_CAPTION 187 +#define IDS_COPY_ERROR_MESSAGE 188 +#define IDS_COPY_ERRMSG_INITIALIZATION_FAILED 189 +#define IDS_COPY_ERRMSG_DIRECTORYCREATE_FAILED 190 +#define IDS_COPY_ERRMSG_COPYFILE_FAILED 191 +#define IDS_COPY_ERRMSG_TITLEFORMAT_FAILED 192 +#define IDS_COPY_ERRMSG_ADDTOMLDB_FAILED 193 +#define IDS_COPY_ERRMSG_SETATTRIBUTES_FAILED 194 +#define IDS_COPY_ERRMSG_COPYFILE_USERABORT 195 +#define IDS_COPY_ERRMSG_DELETEFILE_FAILED 196 +#define IDS_CONFIRM_CREATE_DESTINATION 197 +#define IDS_DESTINATION_NOT_EXIST_FORMAT 198 +#define IDS_CANCEL 199 +#define IDS_SKIP 200 +#define IDS_OVERWRITE 201 +#define IDS_APPLY_TO_ALL_FILES 202 +#define IDS_CONFIRM_FILE_REPLACE 203 +#define IDS_FILE_REPLACE_FORMAT 204 +#define IDS_CONFIRM_FILE_DELETE 205 +#define IDS_READONLY_FILE_DELETE_FORMAT 206 +#define IDS_SIZE 207 +#define IDS_CREATED 208 +#define IDS_MODIFIED 209 +#define IDS_UNKNOWN_GENRE 210 +#define IDS_YOU_ARE_CURRENTLY_COPYING_DATA_CD_MUST_CANCEL_TO_CLOSE_WINAMP 211 +#define IDS_YOU_ARE_CURRENTLY_RIPPING_AUDIO_CD_MUST_CANCEL_TO_CLOSE_WINAMP 212 +#define IDS_ERROR_RIPPING_TRACK 213 +#define IDS_NO_INFO_AVAILABLE 214 +#define IDC_LIST2 1001 +#define IDC_BUTTON_PLAY 1002 +#define IDC_BUTTON_ENQUEUE 1003 +#define IDC_BUTTON_EXTRACT 1004 +#define IDC_BUTTON_EJECT 1005 +#define IDC_CDINFO 1006 +#define IDC_CDINFO2 1007 +#define IDC_TAB1 1008 +#define IDC_TOTAL_TRACKS 1008 +#define IDC_DESTPATH 1009 +#define IDC_BUTTON1 1010 +#define IDC_FILENAMEFMT 1011 +#define IDC_BTN_BROWSE 1011 +#define IDC_BUTTON2 1012 +#define IDC_UPPERCASEEXT 1013 +#define IDC_CHECK_ML 1014 +#define IDC_EDT_NAMEFORMAT 1014 +#define IDC_TAGFILES 1015 +#define IDC_BTN_HELP 1015 +#define IDC_AUTO_RG 1016 +#define IDC_CHK_EXTUPPERCASE 1016 +#define IDC_EDIT2 1017 +#define IDC_CHK_CUSTOMNAME 1017 +#define IDC_EDIT1 1018 +#define IDC_MESSAGE2 1018 +#define IDC_CHK_ADDTOMLDB 1018 +#define IDC_FMTOUT 1019 +#define IDC_BTN_SHOWINFO 1019 +#define IDC_CHK_REPLAYGAIN 1019 +#define IDC_ENCFORMAT 1020 +#define IDC_LBL_TEXT 1020 +#define IDC_EDIT3 1020 +#define IDC_ENC_CONFIG 1021 +#define IDC_LV_DETAILS 1022 +#define IDC_STATUS 1023 +#define IDC_CTFRAME 1024 +#define IDC_PROGRESS1 1025 +#define IDC_BTN_PLAY 1025 +#define IDC_BTN_PLAYEX 1025 +#define IDC_PROGRESS2 1026 +#define IDC_BTN_ENQUEUE 1026 +#define IDC_STATUS2 1027 +#define IDC_BTN_EJECT 1027 +#define IDC_CHECK1 1028 +#define IDC_LBL_TEST 1028 +#define IDC_CHECK2 1029 +#define IDC_LIST1 1029 +#define IDC_CHECK3 1030 +#define IDC_COMBO2 1030 +#define IDC_CHECK4 1031 +#define IDC_COMBO3 1031 +#define IDC_CANCEL_RIP 1032 +#define IDC_CUSTOM1 1032 +#define IDC_CURTRACK 1033 +#define IDC_RIPOPTS 1034 +#define IDC_ADD 1035 +#define IDC_VDELIM 1035 +#define IDC_HDELIM 1035 +#define IDC_CLEAR 1036 +#define IDC_BURN 1037 +#define IDC_LOGO 1039 +#define IDC_BURN_OPTS 1040 +#define IDC_CANCEL_BURN 1042 +#define IDC_STAT 1043 +#define IDC_COMBO1 1044 +#define IDC_PRO1 1045 +#define IDC_PRO2 1046 +#define IDC_TEXT 1047 +#define IDC_MESSAGE 1048 +#define IDC_LBL 1048 +#define IDC_LBL_STATUS 1048 +#define IDC_LBL_BANNER 1049 +#define IDC_BTN_COPY 1049 +#define IDC_LBL_DRIVES 1050 +#define IDC_LBL_MESSAGE 1050 +#define IDC_LIST_DRIVES 1051 +#define IDC_BTN_OPTIONS 1051 +#define IDC_LBL_INFO_DRIVE 1052 +#define IDC_EDT_PATH 1052 +#define IDC_LBL_INFO_MEDIUM 1053 +#define IDC_GRP_OPTIONS 1053 +#define IDC_LBL_DRIVE_LETTER 1054 +#define IDC_EDT_TEXT 1054 +#define IDC_LBL_DRIVE_DESCRIPTION 1055 +#define IDC_LBL_CAPTION 1055 +#define IDC_LBL_DRIVE_BUS 1056 +#define IDC_LBL_EXAMPLE 1056 +#define IDC_LBL_DRIVE_TYPES 1057 +#define IDC_LBL_EXAMPLE_TITLE 1057 +#define IDC_LBL_MEDIUM_TYPE 1058 +#define IDC_LBL_FREE_TITLE 1058 +#define IDC_LBL_MEDIUM_FORMAT 1059 +#define IDC_LBL_REQUIRED_TITLE 1059 +#define IDC_LBL_MEDIUM_TRACKN 1060 +#define IDC_LBL_FREE 1060 +#define IDC_LBL_MEDIUM_CAPACITY 1061 +#define IDC_LBL_REQUIRED 1061 +#define IDC_LBL_MEDIUM_RECORDABLE 1062 +#define IDC_PRG_TOTAL 1062 +#define IDC_LBL_MEDIUM_ERASEABLE 1063 +#define IDC_LBL_TASK 1063 +#define IDC_LBL_MEDIUM_ADDINFO 1064 +#define IDC_LBL_OPERATION 1064 +#define IDC_LBL_DRIVE_LETTER_VAL 1065 +#define IDC_RB_GAIN_MODE_ALBUM 1065 +#define IDC_CHECKBOX1 1065 +#define IDC_LBL_DRIVE_DESCRIPTION_VAL 1066 +#define IDC_BTN_EXTRA1 1066 +#define IDC_LBL_DRIVE_BUS_VAL 1067 +#define IDC_PIC_ICON 1067 +#define IDC_LBL_DRIVE_TYPES_VAL 1068 +#define IDC_PIC_LOGO 1068 +#define IDC_LBL_MEDIUM_DISC_VAL 1069 +#define IDC_LBL_MEDIUM_FORMAT_VAL 1070 +#define IDC_LBL_MEDIUM_TRACKN_VAL 1071 +#define IDC_LBL_MEDIUM_CAPACITY_VAL 1072 +#define IDC_LBL_MEDIUM_RECORDABLE_VAL 1073 +#define IDC_LBL_MEDIUM_ERASEABLE_VAL 1074 +#define IDC_LBL_MEDIUM_ADDINFO_VAL 1075 +#define IDC_BTN_REFRESH 1076 +#define IDC_LBL_MEDIUM_UPDATE 1077 +#define IDC_LBL_MEDIUM_ADDINFO_VAL2 1078 +#define IDC_LBL_MEDIUM_NOINFO 1078 +// #define IDB_LOGO_SONIC 1101 +#define IDB_LISTITEM_CDDRIVE 1102 +#define IDB_LISTBOX_BACK 1104 +#define IDB_NAVITEM_CDROM 1106 +#define IDB_EJECT_NORMAL 1107 +#define IDB_EJECT_HILITED 1108 +#define IDB_EJECT_PRESSED 1109 +#define IDB_EJECT_DISABLED 1110 +#define IDB_PLAY_NORMAL 1111 +#define IDB_PLAY_HIGHLIGHTED 1112 +#define IDB_PLAY_DISABLED 1113 +#define IDB_PLAY_PRESSED 1114 +#define IDB_ENQUEUE_PRESSED 1115 +#define IDB_EJECT2_PRESSED 1116 +#define IDB_ENQUEUE_NORMAL 1117 +#define IDB_ENQUEUE_HIGHLIGHTED 1118 +#define IDB_ENQUEUE_DISABLED 1119 +#define IDB_EJECT2_NORMAL 1123 +#define IDB_EJECT2_HIGHLIGHTED 1124 +#define IDB_EJECT2_DISABLED 1125 +#define IDB_PLAY_MENU 1126 +#define IDB_ENQUEUE_MENU 1127 +#define ID_EXTRACTMENU_CONFIGURE 40001 +#define ID_EXTRACTMENU_EXTRACTALLTRACKS 40002 +#define ID_EXTRACTMENU_EXTRACTSELECTEDTRACKS 40003 +#define ID_CDROMMENU_PLAYSELECTEDITEMS 40004 +#define ID_CDROMMENU_ENQUEUESELECTEDITEMS 40005 +#define ID_CDROMMENU_PLAYALL 40006 +#define ID_CDROMMENU_ENQUEUEALL 40007 +#define ID_PE_ID3 40008 +#define ID_CDROMMENU_EXTRACT_EXTRACTSELECTEDITEMS 40009 +#define ID_CDROMMENU_EXTRACT_EXTRACTALL 40010 +#define ID_CDROMMENU_EXTRACT_CONFIGURE 40011 +#define ID_CDROMMENU_EJECTCD 40012 +#define ID_BURNADDMENU_FILES 40013 +#define ID_BURNADDMENU_FOLDER 40014 +#define ID_BURNADDMENU_CURRENTPLAYLIST 40015 +#define ID_BURNCONTEXTMENU_PLAYSELECTEDITEMS 40016 +#define ID_BURNCONTEXTMENU_ENQUEUESELECTEDITEMS 40017 +#define ID_BURNCONTEXTMENU_MOVESELECTEDITEMSUP 40018 +#define ID_BURNCONTEXTMENU_MOVESELECTEDITEMSDOWN 40019 +#define ID_BURNCONTEXTMENU_REMOVESELECTEDITEMS 40020 +#define ID_BURNCONTEXTMENU_BURN 40021 +#define ID_RIPOPTIONS_PRIORITY_HIGH 40022 +#define ID_RIPOPTIONS_PRIORITY_ABOVENORMAL 40023 +#define ID_RIPOPTIONS_PRIORITY_NORMAL 40024 +#define ID_RIPOPTIONS_PRIORITY_BELOWNORMAL 40025 +#define ID_RIPOPTIONS_PRIORITY_LOWEST 40026 +#define ID_RIPOPTIONS_PRIORITY_IDLE 40027 +#define ID_RIPOPTIONS_RIPPINGSTATUSWINDOW 40028 +#define ID_RIPOPTIONS_EJECTCDWHENCOMPLETED 40029 +#define ID_RIPOPTIONS_PLAYTRACKSWHENCOMPLETED 40030 +#define ID_RIPOPTIONS_CLOSEVIEWWHENCOMPLETE 40031 +#define ID_BURNOPTIONS_ADDCDTITLESTOLOCALCDDBCACHE 40032 +#define ID_BURNCONTEXTMENU_SELECTALL 40033 +#define ID_CDROMMENU2_SELECTALL 40034 +#define ID_CDROMMENU_SELECTALL 40035 +#define ID_Menu 40036 +#define ID_DATAVIEWOPTIONS_HIDEEXTENSIONS 40045 +#define ID_DATAVIEWOPTIONS_SHOWHIDDENFILES 40046 +#define ID_DATAVIEWOPTIONS_SHOW 40047 +#define ID_EJECT_DISC 40083 +#define ID_COPY_SELECTION 40085 +#define ID_DRIVE_MODE_CHANGED 40086 +#define ID_NAVIGATION_PREFERENCES 40087 +#define ID_NAVIGATION_HELP 40088 +#define ID_CDROMMENU2_HELP 40089 +#define ID_CDROMMENU_EXTRACT_HELP 40090 +#define ID_MINIINFO_SHOW 40104 +#define IDS_NULLSOFT_RIP_AND_BURN 65534 +#define IDS_COPY_ERROR_MESSSAGE 65535 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 216 +#define _APS_NEXT_COMMAND_VALUE 40091 +#define _APS_NEXT_CONTROL_VALUE 1079 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Src/Plugins/Library/ml_disc/resources/cdrom.png b/Src/Plugins/Library/ml_disc/resources/cdrom.png Binary files differnew file mode 100644 index 00000000..3c5d6856 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/cdrom.png diff --git a/Src/Plugins/Library/ml_disc/resources/cdrom_32x32_24.bmp b/Src/Plugins/Library/ml_disc/resources/cdrom_32x32_24.bmp Binary files differnew file mode 100644 index 00000000..f05dc379 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/cdrom_32x32_24.bmp diff --git a/Src/Plugins/Library/ml_disc/resources/eject1.png b/Src/Plugins/Library/ml_disc/resources/eject1.png Binary files differnew file mode 100644 index 00000000..7db2d8ad --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/eject1.png diff --git a/Src/Plugins/Library/ml_disc/resources/eject2.png b/Src/Plugins/Library/ml_disc/resources/eject2.png Binary files differnew file mode 100644 index 00000000..72bdd140 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/eject2.png diff --git a/Src/Plugins/Library/ml_disc/resources/eject3.png b/Src/Plugins/Library/ml_disc/resources/eject3.png Binary files differnew file mode 100644 index 00000000..54f37222 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/eject3.png diff --git a/Src/Plugins/Library/ml_disc/resources/eject4.png b/Src/Plugins/Library/ml_disc/resources/eject4.png Binary files differnew file mode 100644 index 00000000..b929fbac --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/eject4.png diff --git a/Src/Plugins/Library/ml_disc/resources/eject_d.png b/Src/Plugins/Library/ml_disc/resources/eject_d.png Binary files differnew file mode 100644 index 00000000..6b7c9b45 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/eject_d.png diff --git a/Src/Plugins/Library/ml_disc/resources/eject_n.png b/Src/Plugins/Library/ml_disc/resources/eject_n.png Binary files differnew file mode 100644 index 00000000..dd198f2b --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/eject_n.png diff --git a/Src/Plugins/Library/ml_disc/resources/eject_p.png b/Src/Plugins/Library/ml_disc/resources/eject_p.png Binary files differnew file mode 100644 index 00000000..68aa0c16 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/eject_p.png diff --git a/Src/Plugins/Library/ml_disc/resources/enqueue_d.png b/Src/Plugins/Library/ml_disc/resources/enqueue_d.png Binary files differnew file mode 100644 index 00000000..fe755949 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/enqueue_d.png diff --git a/Src/Plugins/Library/ml_disc/resources/enqueue_menu_16x16.png b/Src/Plugins/Library/ml_disc/resources/enqueue_menu_16x16.png Binary files differnew file mode 100644 index 00000000..d3dd357a --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/enqueue_menu_16x16.png diff --git a/Src/Plugins/Library/ml_disc/resources/enqueue_n.png b/Src/Plugins/Library/ml_disc/resources/enqueue_n.png Binary files differnew file mode 100644 index 00000000..7b7ad057 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/enqueue_n.png diff --git a/Src/Plugins/Library/ml_disc/resources/enqueue_p.png b/Src/Plugins/Library/ml_disc/resources/enqueue_p.png Binary files differnew file mode 100644 index 00000000..12704e8f --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/enqueue_p.png diff --git a/Src/Plugins/Library/ml_disc/resources/enqueuem_d.png b/Src/Plugins/Library/ml_disc/resources/enqueuem_d.png Binary files differnew file mode 100644 index 00000000..0bd93761 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/enqueuem_d.png diff --git a/Src/Plugins/Library/ml_disc/resources/enqueuem_n.png b/Src/Plugins/Library/ml_disc/resources/enqueuem_n.png Binary files differnew file mode 100644 index 00000000..f76d4027 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/enqueuem_n.png diff --git a/Src/Plugins/Library/ml_disc/resources/enqueuem_p.png b/Src/Plugins/Library/ml_disc/resources/enqueuem_p.png Binary files differnew file mode 100644 index 00000000..11f1b4d8 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/enqueuem_p.png diff --git a/Src/Plugins/Library/ml_disc/resources/filecopy.png b/Src/Plugins/Library/ml_disc/resources/filecopy.png Binary files differnew file mode 100644 index 00000000..85d7f746 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/filecopy.png diff --git a/Src/Plugins/Library/ml_disc/resources/listbox_back_2x68x24.bmp b/Src/Plugins/Library/ml_disc/resources/listbox_back_2x68x24.bmp Binary files differnew file mode 100644 index 00000000..6786dbbe --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/listbox_back_2x68x24.bmp diff --git a/Src/Plugins/Library/ml_disc/resources/play_d.png b/Src/Plugins/Library/ml_disc/resources/play_d.png Binary files differnew file mode 100644 index 00000000..f68d02ad --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/play_d.png diff --git a/Src/Plugins/Library/ml_disc/resources/play_menu_16x16.png b/Src/Plugins/Library/ml_disc/resources/play_menu_16x16.png Binary files differnew file mode 100644 index 00000000..20f265dd --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/play_menu_16x16.png diff --git a/Src/Plugins/Library/ml_disc/resources/play_n.png b/Src/Plugins/Library/ml_disc/resources/play_n.png Binary files differnew file mode 100644 index 00000000..b457b984 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/play_n.png diff --git a/Src/Plugins/Library/ml_disc/resources/play_p.png b/Src/Plugins/Library/ml_disc/resources/play_p.png Binary files differnew file mode 100644 index 00000000..e6a33c91 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/play_p.png diff --git a/Src/Plugins/Library/ml_disc/resources/playm_d.png b/Src/Plugins/Library/ml_disc/resources/playm_d.png Binary files differnew file mode 100644 index 00000000..6c279fb7 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/playm_d.png diff --git a/Src/Plugins/Library/ml_disc/resources/playm_n.png b/Src/Plugins/Library/ml_disc/resources/playm_n.png Binary files differnew file mode 100644 index 00000000..a3b219c3 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/playm_n.png diff --git a/Src/Plugins/Library/ml_disc/resources/playm_p.png b/Src/Plugins/Library/ml_disc/resources/playm_p.png Binary files differnew file mode 100644 index 00000000..ece39e30 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/playm_p.png diff --git a/Src/Plugins/Library/ml_disc/resources/rip&burn_logo_228x25x16.bmp b/Src/Plugins/Library/ml_disc/resources/rip&burn_logo_228x25x16.bmp Binary files differnew file mode 100644 index 00000000..ee89767a --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/rip&burn_logo_228x25x16.bmp diff --git a/Src/Plugins/Library/ml_disc/resources/sonic_powered_44x22.bmp b/Src/Plugins/Library/ml_disc/resources/sonic_powered_44x22.bmp Binary files differnew file mode 100644 index 00000000..5ead745e --- /dev/null +++ b/Src/Plugins/Library/ml_disc/resources/sonic_powered_44x22.bmp diff --git a/Src/Plugins/Library/ml_disc/settings.cpp b/Src/Plugins/Library/ml_disc/settings.cpp new file mode 100644 index 00000000..e7fcb40c --- /dev/null +++ b/Src/Plugins/Library/ml_disc/settings.cpp @@ -0,0 +1,573 @@ +#include "main.h" +#include "./settings.h" +#include "./resource.h" +#include <shlwapi.h> +#include <strsafe.h> + +#define SECTION_DEFAULT TEXT("gen_ml_config") +#define SECTION_DATAVIEW TEXT("data_view") +// Keys +#define KEY_EF_PATH TEXT("extractpath") +#define KEY_EF_TITLEFMT TEXT("extractfmt2") +#define KEY_EF_PLAYLISTFMT TEXT("extractplfmt2") +#define KEY_EF_COMMENTTEXT TEXT("tagcomment") +#define KEY_EF_UPPEREXTENSION TEXT("extractucext") +#define KEY_EF_ADDMETADATA TEXT("extracttag") +#define KEY_EF_CALCULATERG TEXT("auto_rg") +#define KEY_EF_USETOTALTRACKS TEXT("total_tracks") +#define KEY_EF_ADDTOMLDB TEXT("extractaddml") +#define KEY_EF_TRACKOFFSET TEXT("trackoffs") +#define KEY_EF_CREATEM3U TEXT("extractm3u") +#define KEY_EF_CREATEPLS TEXT("extractpls") +#define KEY_EF_CREATEMLPL TEXT("extractplml") +#define KEY_EF_USEM3UEXT TEXT("extractm3uext") +#define KEY_EF_FOURCC TEXT("extract4cc") + +// Defeault values +#define DEF_EF_PATH GetDefaultExtractPath() +#define DEF_EF_TITLEFMT TEXT("<Artist> - <Album>\\## - <Trackartist> - <Title>") +#define DEF_EF_PLAYLISTFMT TEXT("<Artist> - <Album>\\<Artist> - <Album>") +#define DEF_EF_COMMENTTEXT TEXT("Ripped by Winamp") +#define DEF_EF_UPPEREXTENSION FALSE +#define DEF_EF_ADDMETADATA TRUE +#define DEF_EF_CALCULATERG FALSE +#define DEF_EF_USETOTALTRACKS FALSE +#define DEF_EF_ADDTOMLDB TRUE +#define DEF_EF_TRACKOFFSET 1 +#define DEF_EF_CREATEM3U TRUE +#define DEF_EF_CREATEPLS FALSE +#define DEF_EF_CREATEMLPL TRUE +#define DEF_EF_USEM3UEXT TRUE +#define DEF_EF_FOURCC mmioFOURCC('A','A','C','f') + + +#define KEY_CF_PATH KEY_EF_PATH +#define KEY_CF_USETITLEFMT TEXT("copy_use_title_fmt") +#define KEY_CF_TITLEFMT TEXT("copy_title_fmt") +#define KEY_CF_ADDTOMLDB TEXT("copy_add_to_mldb") +#define KEY_CF_CALCULATERG TEXT("copy_calc_gain") +#define KEY_CF_GAINMODE TEXT("copy_gain_mode") + +#define DEF_CF_PATH DEF_EF_PATH +#define DEF_CF_USETITLEFMT TRUE +#define DEF_CF_TITLEFMT TEXT("<Artist>\\<Album>\\<Filename><extension>") +#define DEF_CF_ADDTOMLDB DEF_EF_ADDTOMLDB +#define DEF_CF_CALCULATERG DEF_EF_CALCULATERG +#define DEF_CF_GAINMODE 0 + + +#define KEY_GF_SHOWINFO TEXT("showinfo") +#define KEY_GF_SHOWPARENT TEXT("showparent") +#define KEY_GF_ENQUEUEBYDEFAULT TEXT("enqueuedef") + +#define DEF_GF_SHOWINFO FALSE +#define DEF_GF_SHOWPARENT FALSE +#define DEF_GF_ENQUEUEBYDEFAULT FALSE + +#define KEY_DVF_COLUMNLIST TEXT("column_list") +#define KEY_DVF_LASTFOLDER TEXT("last_folder") +#define KEY_DVF_ORDERBY TEXT("column_order_by") +#define KEY_DVF_ORDERASC TEXT("column_order_asc") +#define KEY_DVF_VIEWMODE TEXT("view_mode") +#define KEY_DVF_SHOWAUDIO TEXT("show_audio") +#define KEY_DVF_SHOWVIDEO TEXT("show_video") +#define KEY_DVF_SHOWPLAYLIST TEXT("show_playlist") +#define KEY_DVF_SHOWUNKNOWN TEXT("show_unknown") +#define KEY_DVF_HIDEEXTENSION TEXT("hide_extension") +#define KEY_DVF_IGNOREHIDDEN TEXT("ignore_hidden") +#define KEY_DVF_DIVIDERPOS TEXT("horz_divider_pos") + + +#define DEF_DVF_COLUMNLIST NULL +#define DEF_DVF_LASTFOLDER NULL +#define DEF_DVF_ORDERBY 0 +#define DEF_DVF_ORDERASC TRUE +#define DEF_DVF_VIEWMODE -1 +#define DEF_DVF_SHOWAUDIO TRUE +#define DEF_DVF_SHOWVIDEO TRUE +#define DEF_DVF_SHOWPLAYLIST TRUE +#define DEF_DVF_SHOWUNKNOWN FALSE +#define DEF_DVF_HIDEEXTENSION TRUE +#define DEF_DVF_IGNOREHIDDEN TRUE +#define DEF_DVF_DIVIDERPOS 240 + + +// configs +#define GLOBAL g_config +#define VIEW g_view_metaconf + +// readers +#define READ_LPTSTR(config) (config)->ReadCbStringEx +#define READ_QUOTED_LPTSTR(config) (config)->ReadCbQuotedString +#define GET_INT(config) (config)->ReadIntEx +#define GET_BOOL(config) (config)->ReadBoolEx + +// writers +#define WRITE_LPCTSTR(config) (config)->WriteStringEx +#define WRITE_QUOTED_LPCTSTR(config) (config)->WriteQuotedString +#define WRITE_INT(config) (config)->WriteIntEx +#define WRITE_BOOL(config) (config)->WriteBoolEx + + +#define CHECK_EXREAD(type, config, section, field, buffer, cb) case field##: READ_##type##(config)(((##type##)buffer), cb, section, KEY_##field, DEF_##field); return S_OK; +#define CHECK_EXREAD_QUOTED(type, config, section, field, buffer, cb) case field##: READ_QUOTED_##type##(config)(((##type##)buffer), cb, section, KEY_##field, DEF_##field); return S_OK; +#define CHECK_EXGET(type, config, section, field, result) case field##: *((##type##*)result) = GET_##type##(config)(section, KEY_##field, DEF_##field); return S_OK; +#define CHECK_EXWRITE(type, config, section, field, value) case field##: WRITE_##type##(config)(section, KEY_##field, value); return S_OK; +#define CHECK_EXWRITE_QUOTED(type, config, section, field, value) case field##: WRITE_QUOTED_##type##(config)(section, KEY_##field, value); return S_OK; + +#define CHECK_DEFAULT(type, field, result) case field##: *((##type##*)result) = DEF_##field; return S_OK; +#define CHECK_READ(type, config, field, buffer, cb) CHECK_EXREAD(type, config, SECTION_DEFAULT, field, buffer, cb) +#define CHECK_READ_QUOTED(type, config, field, buffer, cb) CHECK_EXREAD_QUOTED(type, config, SECTION_DEFAULT, field, buffer, cb) +#define CHECK_GET(type, config, field, result) CHECK_EXGET(type, config, SECTION_DEFAULT, field, result) +#define CHECK_WRITE(type, config, field, value) CHECK_EXWRITE(type, config, SECTION_DEFAULT, field, value) +#define CHECK_WRITE_QUOTED(type, config, field, value) CHECK_EXWRITE_QUOTED(type, config, SECTION_DEFAULT, field, value) + +#define CHECK_EXREAD_VIEW(type, section, field, buffer, cb) CHECK_EXREAD(type, VIEW, section, field, buffer, cb) +#define CHECK_EXGET_VIEW(type, section, field, result) CHECK_EXGET(type, VIEW, section, field, result) +#define CHECK_EXWRITE_VIEW(type, section, field, value) CHECK_EXWRITE(type, VIEW, section, field, value) + +#define CHECK_READ_GLOBAL(type, field, buffer, cb) CHECK_READ(type, GLOBAL, field, buffer, cb) +#define CHECK_READ_QUOTED_GLOBAL(type, field, buffer, cb) CHECK_READ_QUOTED(type, GLOBAL, field, buffer, cb) +#define CHECK_GET_GLOBAL(type, field, result) CHECK_GET(type, GLOBAL, field, result) +#define CHECK_READ_VIEW(type, field, buffer, cb) CHECK_READ(type, VIEW, field, buffer, cb) +#define CHECK_GET_VIEW(type, field, result) CHECK_GET(type, VIEW, field, result) +#define CHECK_WRITE_GLOBAL(type, field, value) CHECK_WRITE(type, GLOBAL, field, value) +#define CHECK_WRITE_QUOTED_GLOBAL(type, field, value) CHECK_WRITE_QUOTED(type, GLOBAL, field, value) +#define CHECK_WRITE_VIEW(type, field, value) CHECK_WRITE(type, VIEW, field, value) + +#define STR_CHECK_DEFAULT(field, result) CHECK_DEFAULT(LPCTSTR, field, result) +#define INT_CHECK_DEFAULT(field, result) CHECK_DEFAULT(INT, field, result) +#define BOOL_CHECK_DEFAULT(field, result) CHECK_DEFAULT(BOOL, field, result) + +#define STR_CHECK_READ_GLOBAL(field, buffer, cb) CHECK_READ_GLOBAL(LPTSTR, field, buffer, cb) +#define STR_CHECK_READ_QUOTED_GLOBAL(field, buffer, cb) CHECK_READ_QUOTED_GLOBAL(LPTSTR, field, buffer, cb) +#define INT_CHECK_GET_GLOBAL(field, result) CHECK_GET_GLOBAL(INT, field, result) +#define BOOL_CHECK_GET_GLOBAL(field, result) CHECK_GET_GLOBAL(BOOL, field, result) + +#define STR_CHECK_WRITE_GLOBAL(field, value) CHECK_WRITE_GLOBAL(LPCTSTR, field, value) +#define STR_CHECK_WRITE_QUOTED_GLOBAL(field, value) CHECK_WRITE_QUOTED_GLOBAL(LPCTSTR, field, value) +#define INT_CHECK_WRITE_GLOBAL(field, value) CHECK_WRITE_GLOBAL(INT, field, value) +#define BOOL_CHECK_WRITE_GLOBAL(field, value) CHECK_WRITE_GLOBAL(BOOL, field, value) + +#define STR_CHECK_EXREAD_VIEW(section, field, buffer, cb) CHECK_EXREAD_VIEW(LPTSTR, section, field, buffer, cb) +#define INT_CHECK_EXGET_VIEW(section, field, result) CHECK_EXGET_VIEW(INT, section, field, result) +#define BOOL_CHECK_EXGET_VIEW(section, field, result) CHECK_EXGET_VIEW(BOOL, section, field, result) + +#define STR_CHECK_EXWRITE_VIEW(section, field, value) CHECK_EXWRITE_VIEW(LPCTSTR, section, field, value) +#define INT_CHECK_EXWRITE_VIEW(section, field, value) CHECK_EXWRITE_VIEW(INT, section, field, value) +#define BOOL_CHECK_EXWRITE_VIEW(section, field, value) CHECK_EXWRITE_VIEW(BOOL, section, field, value) + +#define STR_CHECK_READ_VIEW(field, buffer, cb) CHECK_READ_VIEW(LPTSTR, field, buffer, cb) +#define INT_CHECK_GET_VIEW(field, result) CHECK_GET_VIEW(INT, field, result) +#define BOOL_CHECK_GET_VIEW(field, result) CHECK_GET_VIEW(BOOL, field, result) + +#define STR_CHECK_WRITE_VIEW(field, value) CHECK_WRITE_VIEW(LPCTSTR, field, value) +#define INT_CHECK_WRITE_VIEW(field, value) CHECK_WRITE_VIEW(INT, field, value) +#define BOOL_CHECK_WRITE_VIEW(field, value) CHECK_WRITE_VIEW(BOOL, field, value) + +static LPCWSTR GetDefaultExtractPath() +{ + static TCHAR m_def_extract_path[MAX_PATH] = { TEXT('\0'), }; + + if (L'\0' == m_def_extract_path[0]) + { + if(FAILED(SHGetFolderPath(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, m_def_extract_path))) + { + if(FAILED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, m_def_extract_path))) + { + // and if that all fails then do a reasonable default + StringCchCopyW(m_def_extract_path, ARRAYSIZE(m_def_extract_path), L"C:\\My Music"); + } + // if there's no valid My Music folder (typically win2k) then default to %my_documents%\my music + else PathCombineW(m_def_extract_path, m_def_extract_path, L"My Music"); + } + } + return m_def_extract_path; +} + +HRESULT Settings_GetDefault(INT categoryId, INT fieldId, VOID *pValue) +{ + switch(categoryId) + { + case C_EXTRACT: + switch(fieldId) + { + STR_CHECK_DEFAULT(EF_PATH, pValue); + STR_CHECK_DEFAULT(EF_TITLEFMT, pValue); + STR_CHECK_DEFAULT(EF_PLAYLISTFMT, pValue); + STR_CHECK_DEFAULT(EF_COMMENTTEXT, pValue); + BOOL_CHECK_DEFAULT(EF_UPPEREXTENSION, pValue); + BOOL_CHECK_DEFAULT(EF_ADDMETADATA, pValue); + BOOL_CHECK_DEFAULT(EF_CALCULATERG, pValue); + BOOL_CHECK_DEFAULT(EF_USETOTALTRACKS, pValue); + BOOL_CHECK_DEFAULT(EF_ADDTOMLDB, pValue); + INT_CHECK_DEFAULT(EF_TRACKOFFSET, pValue); + BOOL_CHECK_DEFAULT(EF_CREATEM3U, pValue); + BOOL_CHECK_DEFAULT(EF_CREATEPLS, pValue); + BOOL_CHECK_DEFAULT(EF_CREATEMLPL, pValue); + BOOL_CHECK_DEFAULT(EF_USEM3UEXT, pValue); + INT_CHECK_DEFAULT(EF_FOURCC, pValue); + } + break; + case C_COPY: + switch(fieldId) + { + STR_CHECK_DEFAULT(CF_PATH, pValue); + STR_CHECK_DEFAULT(CF_TITLEFMT, pValue); + BOOL_CHECK_DEFAULT(CF_USETITLEFMT, pValue); + BOOL_CHECK_DEFAULT(CF_ADDTOMLDB, pValue); + BOOL_CHECK_DEFAULT(CF_CALCULATERG, pValue); + INT_CHECK_DEFAULT(CF_GAINMODE, pValue); + } + break; + case C_GLOBAL: + switch(fieldId) + { + BOOL_CHECK_DEFAULT(GF_SHOWINFO, pValue); + BOOL_CHECK_DEFAULT(GF_SHOWPARENT, pValue); + BOOL_CHECK_DEFAULT(GF_ENQUEUEBYDEFAULT, pValue); + } + break; + case C_DATAVIEW: + switch(fieldId) + { + STR_CHECK_DEFAULT(DVF_COLUMNLIST, pValue); + STR_CHECK_DEFAULT(DVF_LASTFOLDER, pValue); + INT_CHECK_DEFAULT(DVF_ORDERBY, pValue); + BOOL_CHECK_DEFAULT(DVF_ORDERASC, pValue); + INT_CHECK_DEFAULT(DVF_VIEWMODE, pValue); + BOOL_CHECK_DEFAULT(DVF_SHOWAUDIO, pValue); + BOOL_CHECK_DEFAULT(DVF_SHOWVIDEO, pValue); + BOOL_CHECK_DEFAULT(DVF_SHOWPLAYLIST, pValue); + BOOL_CHECK_DEFAULT(DVF_SHOWUNKNOWN, pValue); + BOOL_CHECK_DEFAULT(DVF_HIDEEXTENSION, pValue); + BOOL_CHECK_DEFAULT(DVF_IGNOREHIDDEN, pValue); + INT_CHECK_DEFAULT(DVF_DIVIDERPOS, pValue); + } + break; + } + return E_INVALIDARG; +} + + +HRESULT Settings_ReadValue(INT categoryId, INT fieldId, VOID *pValue, INT cbSize) +{ + LPCTSTR pszSection; + switch(categoryId) + { + case C_EXTRACT: + switch(fieldId) + { + STR_CHECK_READ_GLOBAL(EF_PATH, pValue, cbSize); + STR_CHECK_READ_QUOTED_GLOBAL(EF_TITLEFMT, pValue, cbSize); + STR_CHECK_READ_QUOTED_GLOBAL(EF_PLAYLISTFMT, pValue, cbSize); + STR_CHECK_READ_QUOTED_GLOBAL(EF_COMMENTTEXT, pValue, cbSize); + BOOL_CHECK_GET_GLOBAL(EF_UPPEREXTENSION, pValue); + BOOL_CHECK_GET_GLOBAL(EF_ADDMETADATA, pValue); + BOOL_CHECK_GET_GLOBAL(EF_CALCULATERG, pValue); + BOOL_CHECK_GET_GLOBAL(EF_USETOTALTRACKS, pValue); + BOOL_CHECK_GET_GLOBAL(EF_ADDTOMLDB, pValue); + INT_CHECK_GET_GLOBAL(EF_TRACKOFFSET, pValue); + BOOL_CHECK_GET_GLOBAL(EF_CREATEM3U, pValue); + BOOL_CHECK_GET_GLOBAL(EF_CREATEPLS, pValue); + BOOL_CHECK_GET_GLOBAL(EF_CREATEMLPL, pValue); + BOOL_CHECK_GET_GLOBAL(EF_USEM3UEXT, pValue); + INT_CHECK_GET_GLOBAL(EF_FOURCC, pValue); + } + break; + case C_COPY: + switch(fieldId) + { + STR_CHECK_READ_GLOBAL(CF_PATH, pValue, cbSize); + STR_CHECK_READ_QUOTED_GLOBAL(CF_TITLEFMT, pValue, cbSize); + BOOL_CHECK_GET_GLOBAL(CF_USETITLEFMT, pValue); + BOOL_CHECK_GET_GLOBAL(CF_ADDTOMLDB, pValue); + BOOL_CHECK_GET_GLOBAL(CF_CALCULATERG, pValue); + INT_CHECK_GET_GLOBAL(CF_GAINMODE, pValue); + } + break; + case C_GLOBAL: + switch(fieldId) + { + BOOL_CHECK_GET_VIEW(GF_SHOWINFO, pValue); + BOOL_CHECK_GET_VIEW(GF_SHOWPARENT, pValue); + BOOL_CHECK_GET_GLOBAL(GF_ENQUEUEBYDEFAULT, pValue); + } + break; + case C_DATAVIEW: + pszSection = SECTION_DATAVIEW; + switch(fieldId) + { + STR_CHECK_EXREAD_VIEW(pszSection, DVF_COLUMNLIST, pValue, cbSize); + STR_CHECK_EXREAD_VIEW(pszSection, DVF_LASTFOLDER, pValue, cbSize); + INT_CHECK_EXGET_VIEW(pszSection, DVF_ORDERBY, pValue); + BOOL_CHECK_EXGET_VIEW(pszSection, DVF_ORDERASC, pValue); + INT_CHECK_EXGET_VIEW(pszSection, DVF_VIEWMODE, pValue); + BOOL_CHECK_EXGET_VIEW(pszSection, DVF_SHOWAUDIO, pValue); + BOOL_CHECK_EXGET_VIEW(pszSection, DVF_SHOWVIDEO, pValue); + BOOL_CHECK_EXGET_VIEW(pszSection, DVF_SHOWPLAYLIST, pValue); + BOOL_CHECK_EXGET_VIEW(pszSection, DVF_SHOWUNKNOWN, pValue); + BOOL_CHECK_EXGET_VIEW(pszSection, DVF_HIDEEXTENSION, pValue); + BOOL_CHECK_EXGET_VIEW(pszSection, DVF_IGNOREHIDDEN, pValue); + INT_CHECK_EXGET_VIEW(pszSection, DVF_DIVIDERPOS, pValue); + } + break; + } + return E_INVALIDARG; +} + +HRESULT Settings_SetString(INT categoryId, INT fieldId, LPCWSTR pszBuffer) +{ + LPCTSTR pszSection; + switch(categoryId) + { + case C_EXTRACT: + switch(fieldId) + { + STR_CHECK_WRITE_QUOTED_GLOBAL(EF_PATH, pszBuffer); + STR_CHECK_WRITE_QUOTED_GLOBAL(EF_TITLEFMT, pszBuffer); + STR_CHECK_WRITE_QUOTED_GLOBAL(EF_PLAYLISTFMT, pszBuffer); + STR_CHECK_WRITE_QUOTED_GLOBAL(EF_COMMENTTEXT, pszBuffer); + STR_CHECK_WRITE_GLOBAL(EF_UPPEREXTENSION, pszBuffer); + STR_CHECK_WRITE_GLOBAL(EF_ADDMETADATA, pszBuffer); + STR_CHECK_WRITE_GLOBAL(EF_CALCULATERG, pszBuffer); + STR_CHECK_WRITE_GLOBAL(EF_USETOTALTRACKS, pszBuffer); + STR_CHECK_WRITE_GLOBAL(EF_ADDTOMLDB, pszBuffer); + STR_CHECK_WRITE_GLOBAL(EF_TRACKOFFSET, pszBuffer); + STR_CHECK_WRITE_GLOBAL(EF_CREATEM3U, pszBuffer); + STR_CHECK_WRITE_GLOBAL(EF_CREATEPLS, pszBuffer); + STR_CHECK_WRITE_GLOBAL(EF_CREATEMLPL, pszBuffer); + STR_CHECK_WRITE_GLOBAL(EF_USEM3UEXT, pszBuffer); + STR_CHECK_WRITE_GLOBAL(EF_FOURCC, pszBuffer); + } + break; + case C_COPY: + switch(fieldId) + { + STR_CHECK_WRITE_QUOTED_GLOBAL(CF_PATH, pszBuffer); + STR_CHECK_WRITE_QUOTED_GLOBAL(CF_TITLEFMT, pszBuffer); + STR_CHECK_WRITE_GLOBAL(CF_USETITLEFMT, pszBuffer); + STR_CHECK_WRITE_GLOBAL(CF_ADDTOMLDB, pszBuffer); + STR_CHECK_WRITE_GLOBAL(CF_CALCULATERG, pszBuffer); + STR_CHECK_WRITE_GLOBAL(CF_GAINMODE, pszBuffer); + } + break; + case C_GLOBAL: + switch(fieldId) + { + STR_CHECK_WRITE_VIEW(GF_SHOWINFO, pszBuffer); + STR_CHECK_WRITE_VIEW(GF_SHOWPARENT, pszBuffer); + STR_CHECK_WRITE_VIEW(GF_ENQUEUEBYDEFAULT, pszBuffer); + } + break; + case C_DATAVIEW: + pszSection = SECTION_DATAVIEW; + switch(fieldId) + { + STR_CHECK_EXWRITE_VIEW(pszSection, DVF_COLUMNLIST, pszBuffer); + STR_CHECK_EXWRITE_VIEW(pszSection, DVF_LASTFOLDER, pszBuffer); + STR_CHECK_EXWRITE_VIEW(pszSection, DVF_ORDERBY, pszBuffer); + STR_CHECK_EXWRITE_VIEW(pszSection, DVF_ORDERASC, pszBuffer); + STR_CHECK_EXWRITE_VIEW(pszSection, DVF_VIEWMODE, pszBuffer); + STR_CHECK_EXWRITE_VIEW(pszSection, DVF_SHOWAUDIO, pszBuffer); + STR_CHECK_EXWRITE_VIEW(pszSection, DVF_SHOWVIDEO, pszBuffer); + STR_CHECK_EXWRITE_VIEW(pszSection, DVF_SHOWPLAYLIST, pszBuffer); + STR_CHECK_EXWRITE_VIEW(pszSection, DVF_SHOWUNKNOWN, pszBuffer); + STR_CHECK_EXWRITE_VIEW(pszSection, DVF_HIDEEXTENSION, pszBuffer); + STR_CHECK_EXWRITE_VIEW(pszSection, DVF_IGNOREHIDDEN, pszBuffer); + STR_CHECK_EXWRITE_VIEW(pszSection, DVF_DIVIDERPOS, pszBuffer); + } + break; + } + return E_INVALIDARG; +} + + +HRESULT Settings_GetInt(INT categoryId, INT fieldId, INT *pnVal) +{ + return Settings_ReadValue(categoryId, fieldId, pnVal, sizeof(INT)); +} +HRESULT Settings_GetBool(INT categoryId, INT fieldId, BOOL *pbVal) +{ + return Settings_ReadValue(categoryId, fieldId, pbVal, sizeof(BOOL)); +} + +HRESULT Settings_ReadString(INT categoryId, INT fieldId, LPTSTR pszBuffer, INT cchBufferMax) +{ + return Settings_ReadValue(categoryId, fieldId, pszBuffer, cchBufferMax * sizeof(TCHAR)); +} + +HRESULT Settings_SetWindowText(INT categoryId, INT fieldId, HWND hwnd) +{ + TCHAR szBuffer[8192] = {0}; + HRESULT hr = Settings_ReadValue(categoryId, fieldId, szBuffer, sizeof(szBuffer)); + if (S_OK == hr) SetWindowText(hwnd, szBuffer); + return hr; +} + +HRESULT Settings_SetWindowInt(INT categoryId, INT fieldId, HWND hwnd) +{ + INT nVal; + HRESULT hr = Settings_ReadValue(categoryId, fieldId, &nVal, sizeof(nVal)); + + if (S_OK == hr) + { + TCHAR szBuffer[256] = {0}; + hr = StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), TEXT("%d"), nVal); + if (S_OK == hr) SetWindowText(hwnd, szBuffer); + } + return hr; +} +HRESULT Settings_SetDlgItemText(INT categoryId, INT fieldId, HWND hdlg, INT nItemId) +{ + HWND hctrl = GetDlgItem(hdlg, nItemId); + return (hctrl) ? Settings_SetWindowText(categoryId, fieldId, hctrl) : E_HANDLE; +} + +HRESULT Settings_SetDlgItemInt(INT categoryId, INT fieldId, HWND hdlg, INT nItemId) +{ + HWND hctrl = GetDlgItem(hdlg, nItemId); + return (hctrl) ? Settings_SetWindowInt(categoryId, fieldId, hctrl) : E_HANDLE; +} + +HRESULT Settings_SetCheckBox(INT categoryId, INT fieldId, HWND hdlg, INT nItemId) +{ + INT nVal; + HRESULT hr = Settings_GetInt(categoryId, fieldId, &nVal); + if (S_OK == hr) hr = (CheckDlgButton(hdlg, nItemId, (0 != nVal) ? BST_CHECKED : BST_UNCHECKED)) ? S_OK : E_HANDLE; + return hr; +} + +HRESULT Settings_SetInt(INT categoryId, INT fieldId, INT nValue) +{ + TCHAR szBuffer[64] = {0}; + HRESULT hr = StringCchPrintfW(szBuffer, ARRAYSIZE(szBuffer), TEXT("%d"), nValue); + if (S_OK == hr) hr = Settings_SetString(categoryId, fieldId, szBuffer); + return hr; +} +HRESULT Settings_SetBool(INT categoryId, INT fieldId, BOOL bValue) +{ + return Settings_SetInt(categoryId, fieldId, (0 != bValue)); +} +HRESULT Settings_FromWindowText(INT categoryId, INT fieldId, HWND hwnd) +{ + if (!hwnd) return E_HANDLE; + INT l = GetWindowTextLength(hwnd); + if (l < 1024) + { + TCHAR szBuffer[1024] = {0}; + GetWindowText(hwnd, szBuffer, ARRAYSIZE(szBuffer)); + return Settings_SetString(categoryId, fieldId, szBuffer); + } + else + { + LPTSTR pszBuffer = (LPTSTR)calloc((l + 1), sizeof(TCHAR)); + if (!pszBuffer) return E_OUTOFMEMORY; + GetWindowText(hwnd, pszBuffer, sizeof(TCHAR)*(l + 1)); + HRESULT hr = Settings_SetString(categoryId, fieldId, pszBuffer); + free(pszBuffer); + return hr; + } +} +HRESULT Settings_FromDlgItemText(INT categoryId, INT fieldId, HWND hdlg, INT nItemId) +{ + HWND hctrl = GetDlgItem(hdlg, nItemId); + return (hctrl) ? Settings_FromWindowText(categoryId, fieldId, hctrl) : E_HANDLE; +} + +HRESULT Settings_FromCheckBox(INT categoryId, INT fieldId, HWND hdlg, INT nItemId) +{ + UINT v = IsDlgButtonChecked(hdlg, nItemId); + return Settings_SetInt(categoryId, fieldId, v); +} + +typedef struct _FBROWSER +{ + LPCWSTR pszSelection; +} FBROWSER; + +BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam) +{ + wchar_t cl[32] = {0}; + GetClassNameW(hwnd, cl, ARRAYSIZE(cl)); + if (!lstrcmpiW(cl, WC_TREEVIEW)) + { + PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd)); + return FALSE; + } + + return TRUE; +} + +int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM pData) +{ + FBROWSER *pfb = (FBROWSER*)pData; + switch(uMsg) + { + case BFFM_INITIALIZED: + if (pfb && pfb->pszSelection) SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM)pfb->pszSelection); + + // this is not nice but it fixes the selection not working correctly on all OSes + EnumChildWindows(hwnd, browseEnumProc, 0); + break; + } + return 0; +} + +HRESULT Settings_BrowseForFolder(INT categoryId, INT fieldId, HWND hDlg, INT nEditId) +{ + BROWSEINFO bi = {0}; + FBROWSER fb; + wchar_t szPath[MAX_PATH] = {0}; + + HRESULT hr = Settings_ReadString(categoryId,fieldId, szPath, ARRAYSIZE(szPath)); + if (S_OK != hr) return hr; + + fb.pszSelection = szPath; + + bi.hwndOwner = hDlg; + bi.pidlRoot = NULL; + bi.pszDisplayName = szPath; + bi.lpszTitle = WASABI_API_LNGSTRINGW(IDS_CHOOSE_A_FOLDER); + bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_RETURNFSANCESTORS | BIF_NEWDIALOGSTYLE; + bi.lpfn = BrowseCallbackProc; + bi.lParam = (LPARAM)&fb; + HRESULT hrCom = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (SUCCEEDED(hrCom)) + { + ITEMIDLIST *idlist = SHBrowseForFolder(&bi); + if (idlist) + { + if (SHGetPathFromIDList(idlist, szPath)) + { + hr = Settings_SetString(categoryId,fieldId, szPath); + if (S_OK == hr) SetDlgItemText(hDlg, nEditId, szPath); + } + else hr = S_FALSE; + CoTaskMemFree(idlist); + } + } + else hr = hrCom; + if (S_OK == hrCom) CoUninitialize(); + return hr; +} + +HRESULT Settings_SetDirectoryCtrl(INT categoryId, INT fieldId, HWND hdlg, INT nItemId) +{ + TCHAR szBuffer[MAX_PATH] = {0}; + HRESULT hr; + hr = Settings_ReadString(categoryId, fieldId, szBuffer, ARRAYSIZE(szBuffer)); + if (S_OK != hr) *szBuffer = TEXT('\0'); + else CleanupDirectoryString(szBuffer); + SetDlgItemText(hdlg, nItemId, szBuffer); + return hr; +} +HRESULT Settings_FromDirectoryCtrl(INT categoryId, INT fieldId, HWND hdlg, INT nItemId) +{ + TCHAR szBuffer[MAX_PATH] = {0}; + GetDlgItemText(hdlg, nItemId, szBuffer, ARRAYSIZE(szBuffer)); + CleanupDirectoryString(szBuffer); + return Settings_SetString(categoryId, fieldId, szBuffer); +} + + diff --git a/Src/Plugins/Library/ml_disc/settings.h b/Src/Plugins/Library/ml_disc/settings.h new file mode 100644 index 00000000..86aafa7a --- /dev/null +++ b/Src/Plugins/Library/ml_disc/settings.h @@ -0,0 +1,108 @@ +#ifndef NULLOSFT_MEDIALIBRARY_MLDISC_SETTINGS_HEADER +#define NULLOSFT_MEDIALIBRARY_MLDISC_SETTINGS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + +#ifdef __cplusplus +extern "C" { +#endif + + // Groups +enum +{ + C_EXTRACT = 0, + C_COPY, + C_GLOBAL, + C_DATAVIEW, +}; + +// Extract Group Fields +enum +{ + EF_PATH = 0, + EF_TITLEFMT, + EF_PLAYLISTFMT, + EF_UPPEREXTENSION, + EF_ADDMETADATA, + EF_CALCULATERG, + EF_USETOTALTRACKS, + EF_ADDTOMLDB, + EF_TRACKOFFSET, + EF_COMMENTTEXT, + EF_CREATEM3U, + EF_CREATEPLS, + EF_CREATEMLPL, + EF_USEM3UEXT, + EF_FOURCC, +}; + +// Copy Gorup fields +enum +{ + CF_PATH = 0, + CF_USETITLEFMT, + CF_TITLEFMT, + CF_ADDTOMLDB, + CF_CALCULATERG, + CF_GAINMODE, +}; + +// Global group +enum +{ + GF_SHOWINFO = 0, + GF_SHOWPARENT, + GF_ENQUEUEBYDEFAULT, +}; +// Data View flags +enum +{ + DVF_COLUMNLIST = 0, + DVF_ORDERBY, + DVF_ORDERASC, + DVF_VIEWMODE, + DVF_SHOWAUDIO, + DVF_SHOWVIDEO, + DVF_SHOWPLAYLIST, + DVF_SHOWUNKNOWN, + DVF_HIDEEXTENSION, + DVF_IGNOREHIDDEN, + DVF_LASTFOLDER, + DVF_DIVIDERPOS, +}; + +HRESULT Settings_ReadValue(INT categoryId, INT fieldId, VOID *pValue, INT cbSize); +HRESULT Settings_GetDefault(INT categoryId, INT fieldId, VOID *pValue); +HRESULT Settings_ReadString(INT categoryId, INT fieldId, LPTSTR pszBuffer, INT cchBufferMax); +HRESULT Settings_GetInt(INT categoryId, INT fieldId, INT *pnVal); +HRESULT Settings_GetBool(INT categoryId, INT fieldId, BOOL *pbVal); + +HRESULT Settings_SetWindowText(INT categoryId, INT fieldId, HWND hwnd); +HRESULT Settings_SetWindowInt(INT categoryId, INT fieldId, HWND hwnd); +HRESULT Settings_SetDlgItemText(INT categoryId, INT fieldId, HWND hdlg, INT nItemId); +HRESULT Settings_SetDlgItemInt(INT categoryId, INT fieldId, HWND hdlg, INT nItemId); +HRESULT Settings_SetCheckBox(INT categoryId, INT fieldId, HWND hdlg, INT nItemId); + +HRESULT Settings_SetString(INT categoryId, INT fieldId, LPCWSTR pszBuffer); +HRESULT Settings_SetInt(INT categoryId, INT fieldId, INT nValue); +HRESULT Settings_SetBool(INT categoryId, INT fieldId, BOOL bValue); +HRESULT Settings_FromWindowText(INT categoryId, INT fieldId, HWND hwnd); +HRESULT Settings_FromDlgItemText(INT categoryId, INT fieldId, HWND hdlg, INT nItemId); +HRESULT Settings_FromCheckBox(INT categoryId, INT fieldId, HWND hdlg, INT nItemId); +HRESULT Settings_BrowseForFolder(INT categoryId, INT fieldId, HWND hDlg, INT nEditId); + +HRESULT Settings_SetDirectoryCtrl(INT categoryId, INT fieldId, HWND hdlg, INT nItemId); +HRESULT Settings_FromDirectoryCtrl(INT categoryId, INT fieldId, HWND hdlg, INT nItemId); + + +#ifdef __cplusplus +} +#endif + + + +#endif // NULLOSFT_MEDIALIBRARY_MLDISC_SETTINGS_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/spti.cpp b/Src/Plugins/Library/ml_disc/spti.cpp new file mode 100644 index 00000000..8a34320a --- /dev/null +++ b/Src/Plugins/Library/ml_disc/spti.cpp @@ -0,0 +1,239 @@ +#include "./spti.h" +#include <ntddscsi.h> + + +#define CDB6GENERIC_LENGTH 6 +#define CDB10GENERIC_LENGTH 10 + +#define SETBITON 1 +#define SETBITOFF 0 + +// +// Mode Sense/Select page constants. +// + +#define MODE_PAGE_ERROR_RECOVERY 0x01 +#define MODE_PAGE_DISCONNECT 0x02 +#define MODE_PAGE_FORMAT_DEVICE 0x03 +#define MODE_PAGE_RIGID_GEOMETRY 0x04 +#define MODE_PAGE_FLEXIBILE 0x05 +#define MODE_PAGE_VERIFY_ERROR 0x07 +#define MODE_PAGE_CACHING 0x08 +#define MODE_PAGE_PERIPHERAL 0x09 +#define MODE_PAGE_CONTROL 0x0A +#define MODE_PAGE_MEDIUM_TYPES 0x0B +#define MODE_PAGE_NOTCH_PARTITION 0x0C +#define MODE_SENSE_RETURN_ALL 0x3f +#define MODE_SENSE_CURRENT_VALUES 0x00 +#define MODE_SENSE_CHANGEABLE_VALUES 0x40 +#define MODE_SENSE_DEFAULT_VAULES 0x80 +#define MODE_SENSE_SAVED_VALUES 0xc0 +#define MODE_PAGE_DEVICE_CONFIG 0x10 +#define MODE_PAGE_MEDIUM_PARTITION 0x11 +#define MODE_PAGE_DATA_COMPRESS 0x0f +#define MODE_PAGE_CAPABILITIES 0x2A + +// +// SCSI CDB operation codes +// + +#define SCSIOP_TEST_UNIT_READY 0x00 +#define SCSIOP_REZERO_UNIT 0x01 +#define SCSIOP_REWIND 0x01 +#define SCSIOP_REQUEST_BLOCK_ADDR 0x02 +#define SCSIOP_REQUEST_SENSE 0x03 +#define SCSIOP_FORMAT_UNIT 0x04 +#define SCSIOP_READ_BLOCK_LIMITS 0x05 +#define SCSIOP_REASSIGN_BLOCKS 0x07 +#define SCSIOP_READ6 0x08 +#define SCSIOP_RECEIVE 0x08 +#define SCSIOP_WRITE6 0x0A +#define SCSIOP_PRINT 0x0A +#define SCSIOP_SEND 0x0A +#define SCSIOP_SEEK6 0x0B +#define SCSIOP_TRACK_SELECT 0x0B +#define SCSIOP_SLEW_PRINT 0x0B +#define SCSIOP_SEEK_BLOCK 0x0C +#define SCSIOP_PARTITION 0x0D +#define SCSIOP_READ_REVERSE 0x0F +#define SCSIOP_WRITE_FILEMARKS 0x10 +#define SCSIOP_FLUSH_BUFFER 0x10 +#define SCSIOP_SPACE 0x11 +#define SCSIOP_INQUIRY 0x12 +#define SCSIOP_VERIFY6 0x13 +#define SCSIOP_RECOVER_BUF_DATA 0x14 +#define SCSIOP_MODE_SELECT 0x15 +#define SCSIOP_RESERVE_UNIT 0x16 +#define SCSIOP_RELEASE_UNIT 0x17 +#define SCSIOP_COPY 0x18 +#define SCSIOP_ERASE 0x19 +#define SCSIOP_MODE_SENSE 0x1A +#define SCSIOP_START_STOP_UNIT 0x1B +#define SCSIOP_STOP_PRINT 0x1B +#define SCSIOP_LOAD_UNLOAD 0x1B +#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C +#define SCSIOP_SEND_DIAGNOSTIC 0x1D +#define SCSIOP_MEDIUM_REMOVAL 0x1E +#define SCSIOP_READ_CAPACITY 0x25 +#define SCSIOP_READ 0x28 +#define SCSIOP_WRITE 0x2A +#define SCSIOP_SEEK 0x2B +#define SCSIOP_LOCATE 0x2B +#define SCSIOP_WRITE_VERIFY 0x2E +#define SCSIOP_VERIFY 0x2F +#define SCSIOP_SEARCH_DATA_HIGH 0x30 +#define SCSIOP_SEARCH_DATA_EQUAL 0x31 +#define SCSIOP_SEARCH_DATA_LOW 0x32 +#define SCSIOP_SET_LIMITS 0x33 +#define SCSIOP_READ_POSITION 0x34 +#define SCSIOP_SYNCHRONIZE_CACHE 0x35 +#define SCSIOP_COMPARE 0x39 +#define SCSIOP_COPY_COMPARE 0x3A +#define SCSIOP_WRITE_DATA_BUFF 0x3B +#define SCSIOP_READ_DATA_BUFF 0x3C +#define SCSIOP_CHANGE_DEFINITION 0x40 +#define SCSIOP_READ_SUB_CHANNEL 0x42 +#define SCSIOP_READ_TOC 0x43 +#define SCSIOP_READ_HEADER 0x44 +#define SCSIOP_PLAY_AUDIO 0x45 +#define SCSIOP_PLAY_AUDIO_MSF 0x47 +#define SCSIOP_PLAY_TRACK_INDEX 0x48 +#define SCSIOP_PLAY_TRACK_RELATIVE 0x49 +#define SCSIOP_PAUSE_RESUME 0x4B +#define SCSIOP_LOG_SELECT 0x4C +#define SCSIOP_LOG_SENSE 0x4D +#define SCSIOP_READ_DISC_INFORMATION 0x51 + +typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS +{ + SCSI_PASS_THROUGH spt; + DWORD filler; + UCHAR ucSenseBuf[24]; + UCHAR ucDataBuf[256]; +}SCSI_PASS_THROUGH_WITH_BUFFERS; + +#pragma pack(1) + +typedef struct _CDB_START_STOP_UNIT +{ + UCHAR OperationCode; // 0x1B - SCSIOP_START_STOP_UNIT + UCHAR Immediate : 1; + UCHAR Reserved1 : 4; + UCHAR Lun : 3; + UCHAR Reserved2[2]; + UCHAR Start : 1; + UCHAR LoadEject : 1; + UCHAR Reserved3 : 2; + UCHAR PowerCondition : 4; + UCHAR Control; +} CDB_START_STOP_UNIT; + + +typedef struct _READ_DISC_INFORMATION +{ + UCHAR OperationCode; // 0x51 - SCSIOP_READ_DISC_INFORMATION + UCHAR Reserved1 : 5; + UCHAR Lun : 3; + UCHAR Reserved2[5]; + UCHAR AllocationLength[2]; + UCHAR Control; +} READ_DISC_INFORMATION; + +#pragma pack() + + +BOOL SPTI_TestUnitReady(HANDLE hDevice, BYTE *pbSC, BYTE *pbASC, BYTE *pbASCQ, INT timeOutSec) +{ + INT length; + DWORD returned; + SCSI_PASS_THROUGH_WITH_BUFFERS sptwb; + + if (INVALID_HANDLE_VALUE == hDevice) return FALSE; + + ZeroMemory(&sptwb, sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS)); + sptwb.spt.Length = sizeof(SCSI_PASS_THROUGH); + sptwb.spt.CdbLength = CDB6GENERIC_LENGTH; + sptwb.spt.SenseInfoLength = 24; + sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN; + sptwb.spt.DataTransferLength = 0; + sptwb.spt.TimeOutValue = timeOutSec; + sptwb.spt.DataBufferOffset = ((DWORD)(DWORD_PTR)&sptwb.ucDataBuf) - ((DWORD)(DWORD_PTR)&sptwb); + sptwb.spt.SenseInfoOffset = ((DWORD)(DWORD_PTR)&sptwb.ucSenseBuf) - ((DWORD)(DWORD_PTR)&sptwb); + sptwb.spt.Cdb[0] = SCSIOP_TEST_UNIT_READY; + length = ((DWORD)(DWORD_PTR)&sptwb.ucDataBuf) - ((DWORD)(DWORD_PTR)&sptwb); + DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH, &sptwb, sizeof(SCSI_PASS_THROUGH), &sptwb, length, &returned, FALSE); + + if (pbSC) *pbSC = sptwb.ucSenseBuf[2]; + if (pbASC) *pbASC = sptwb.ucSenseBuf[12]; + if (pbASCQ) *pbASCQ = sptwb.ucSenseBuf[13]; + + return TRUE; +} +BOOL SPTI_StartStopUnit(HANDLE hDevice, BOOL bImmediate, BOOL bLoadEject, BOOL bStart, INT timeOutSec, SENSEINFO *pSense) +{ + INT length; + BOOL status; + DWORD returned; + CDB_START_STOP_UNIT cmd; + SCSI_PASS_THROUGH_WITH_BUFFERS sptwb; + + UNREFERENCED_PARAMETER(pSense); + + if (INVALID_HANDLE_VALUE == hDevice) return FALSE; + + ZeroMemory(&sptwb, sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS)); + ZeroMemory(&cmd, sizeof(CDB_START_STOP_UNIT)); + + sptwb.spt.Length = sizeof(SCSI_PASS_THROUGH); + sptwb.spt.CdbLength = CDB6GENERIC_LENGTH; + sptwb.spt.SenseInfoLength = 24; + sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN; + sptwb.spt.DataTransferLength = 0; + sptwb.spt.TimeOutValue = timeOutSec; + sptwb.spt.DataBufferOffset = ((DWORD)(DWORD_PTR)&sptwb.ucDataBuf) - ((DWORD)(DWORD_PTR)&sptwb); + sptwb.spt.SenseInfoOffset = ((DWORD)(DWORD_PTR)&sptwb.ucSenseBuf) - ((DWORD)(DWORD_PTR)&sptwb); + cmd.OperationCode = SCSIOP_START_STOP_UNIT; + cmd.Immediate = (bImmediate) ? 1 : 0; + cmd.LoadEject= (bLoadEject) ? 1 : 0; + cmd.Start = (bStart) ? 1 : 0; + CopyMemory(sptwb.spt.Cdb, &cmd, sizeof(CDB_START_STOP_UNIT)); + + length = ((DWORD)(DWORD_PTR)&sptwb.ucDataBuf) - ((DWORD)(DWORD_PTR)&sptwb); + status = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH, &sptwb, sizeof(SCSI_PASS_THROUGH), &sptwb, length, &returned, FALSE); + + return status; +} +BOOL SPTI_GetCapabilities(HANDLE hDevice, DWORD *pCap) +{ + INT length = 0; + BOOL status; + DWORD returned = 0; + SCSI_PASS_THROUGH_WITH_BUFFERS sptwb; + + if (INVALID_HANDLE_VALUE == hDevice || !pCap) return FALSE; + + *pCap = 0; + + ZeroMemory(&sptwb, sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS)); + sptwb.spt.Length = sizeof(SCSI_PASS_THROUGH); + sptwb.spt.CdbLength = CDB6GENERIC_LENGTH; + sptwb.spt.SenseInfoLength = 24; + sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN; + sptwb.spt.DataTransferLength = 192; + sptwb.spt.TimeOutValue = 10; //2 sec + sptwb.spt.DataBufferOffset = ((DWORD)(DWORD_PTR)&sptwb.ucDataBuf) - ((DWORD)(DWORD_PTR)&sptwb); + sptwb.spt.SenseInfoOffset = ((DWORD)(DWORD_PTR)&sptwb.ucSenseBuf) - ((DWORD)(DWORD_PTR)&sptwb); + sptwb.spt.Cdb[0] = SCSIOP_MODE_SENSE; + sptwb.spt.Cdb[1] = 0x08; // target shall not return any block descriptors + sptwb.spt.Cdb[2] = MODE_PAGE_CAPABILITIES; + sptwb.spt.Cdb[4] = 192; + + length = ((DWORD)(DWORD_PTR)&sptwb.ucDataBuf) - ((DWORD)(DWORD_PTR)&sptwb) + sptwb.spt.DataTransferLength;; + + status = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH, &sptwb, sizeof(SCSI_PASS_THROUGH), &sptwb, length, &returned, FALSE); + if (!status) return FALSE; + + *pCap = *((DWORD*)&sptwb.ucDataBuf[6]) ; + + return TRUE; +} diff --git a/Src/Plugins/Library/ml_disc/spti.h b/Src/Plugins/Library/ml_disc/spti.h new file mode 100644 index 00000000..8c14e8e1 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/spti.h @@ -0,0 +1,35 @@ +#ifndef NULLOSFT_MLDISC_STPI_HEADER +#define NULLOSFT_MLDISC_STPI_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + + +// 02:04:01 - LOGICAL UNIT IS IN PROCESS OF BECOMING READY +// 02:3A:00 - MEDIUM NOT PRESENT +// 02:3A:01 - MEDIUM NOT PRESENT - TRAY CLOSED +// 02:3A:02 - MEDIUM NOT PRESENT - TRAY OPEN +// 06:28:00 - MEDIUM NOT PRESENT - NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED + +typedef struct _SENSEINFO +{ + BYTE bSense; + BYTE bASC; + BYTE bASCQ; +} SENSEINFO; +BOOL SPTI_TestUnitReady(HANDLE hDevice, BYTE *pbSC, BYTE *pbASC, BYTE *pbASCQ, INT timeOutSec); +BOOL SPTI_StartStopUnit(HANDLE hDevice, BOOL bImmediate, BOOL bLoadEject, BOOL bStart, INT timeOutSec, SENSEINFO *pSense); +BOOL SPTI_GetCapabilities(HANDLE hDevice, DWORD *pCap); + +// links to read: +// http://www.t10.org/ftp/t10/drafts/mmc3/mmc3r10g.pdf +// http://www.reactos.org/generated/doxygen/da/db8/scsi_8h-source.html +// http://www.vbarchiv.net/workshop/workshop78s4.html +// http://files.codes-sources.com/fichier.aspx?id=26141&f=Graver.h +// http://files.codes-sources.com/fichier.aspx?id=26141&f=Graver.cpp +// http://www.hackingtruths.org/files/cd_cracking/SRC/etc/DDK.SPTI/spti.c + +#endif //NULLOSFT_MLDISC_STPI_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/version.rc2 b/Src/Plugins/Library/ml_disc/version.rc2 new file mode 100644 index 00000000..efe64048 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/version.rc2 @@ -0,0 +1,39 @@ + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +#include "../../../Winamp/buildType.h" +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,0,0,1 + PRODUCTVERSION WINAMP_PRODUCTVER + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Winamp SA" + VALUE "FileDescription", "Winamp Media Library Plug-in" + VALUE "FileVersion", "2,0,0,1" + VALUE "InternalName", "Nullsoft Rip & Burn" + VALUE "LegalCopyright", "Copyright © 2003-2023 Winamp SA" + VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA" + VALUE "OriginalFilename", "ml_disc.dll" + VALUE "ProductName", "Winamp" + VALUE "ProductVersion", STR_WINAMP_PRODUCTVER + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/Src/Plugins/Library/ml_disc/view_cdrom.cpp b/Src/Plugins/Library/ml_disc/view_cdrom.cpp new file mode 100644 index 00000000..a980aef0 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/view_cdrom.cpp @@ -0,0 +1,1014 @@ +#include <shlwapi.h> + +#include "main.h" +#include <windowsx.h> +#include "resource.h" +#include "../nu/DialogSkinner.h" +#include "../nu/ChildSizer.h" +#include "../winamp/wa_ipc.h" +#include "../Winamp/strutil.h" +#include "../nu/AutoChar.h" +#include "../nu/AutoWide.h" +#include "../nu/listview.h" +#include <strsafe.h> + +#ifndef LVS_EX_DOUBLEBUFFER +#define LVS_EX_DOUBLEBUFFER 0x00010000 +#endif + +static INT_PTR WINAPI DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#define TIMER_NOTIFYINFO_ID 1985 +#define TIMER_NOTIFYINFO_DELAY 200 + +HWND CreateCDViewWindow(HWND hwndParent, DM_NOTIFY_PARAM *phdr) +{ + return WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_CDROM, hwndParent, DlgProc, (LPARAM)phdr); +} + +void TAG_FMT(void *f, void *ff, void *p, char *out, int out_len) +{ + waFormatTitle fmt; + fmt.out = out; + fmt.out_len = out_len; + fmt.p = p; + fmt.spec = 0; + *(void **)&fmt.TAGFUNC = f; + *(void **)&fmt.TAGFREEFUNC = ff; + *out = 0; + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&fmt, IPC_FORMAT_TITLE); +} + + +static wchar_t m_artist[128], m_album[128], m_genre[128], m_year[32]; +static int m_start_immediate_extract = 0; +static int m_atracks, m_dtracks; + + +void CopyComment(wchar_t *&dest, wchar_t *comments) +{ + if (comments) + { + int numCarriageReturns = 0; + wchar_t *commentCursor = comments; + while (commentCursor && *commentCursor) + { + if (*commentCursor == '\r') + { + commentCursor++; + if (*commentCursor == '\n') + commentCursor++; + } + if (*commentCursor == '\n') + numCarriageReturns++; + + commentCursor = CharNext(commentCursor); + } + size_t size = commentCursor - comments; + dest = (wchar_t *)calloc((size + numCarriageReturns + 1), sizeof(wchar_t)); + wchar_t *destCursor = dest; + commentCursor = comments; + while (commentCursor && *commentCursor) + { + if (*commentCursor == '\r') + { + *destCursor++ = *commentCursor++; + if (*commentCursor == '\n') + *destCursor++ = *commentCursor++; + } + if (*commentCursor == '\n') + *destCursor++ = '\r'; + + wchar_t *next = CharNextW(commentCursor); + while (commentCursor != next) + { + *destCursor++ = *commentCursor++; + } + } + *destCursor = 0; + } + else + dest = 0; +} + +static void extractFiles(HWND hwndDlg, CHAR cLetter, int all) +{ + HWND hwndList; + hwndList = GetDlgItem(hwndDlg, IDC_LIST2); + + char cMode; + wchar_t title[32] = {0}, buf[512] = {0}; + INT msgTextId, l, i, cnt = 0; + cdrip_params *p; + wchar_t info[65536] = {0}; + + LVITEMW lvitem = {0}; + + cMode = DriveManager_GetDriveMode(cLetter); + + switch (cMode) + { + case DM_MODE_BURNING: msgTextId = IDS_ERROR_CD_RIP_IN_PROGRESS; break; + case DM_MODE_RIPPING: msgTextId = IDS_ERROR_CD_BURN_IN_PROGRESS; break; + default: msgTextId = 0; break; + } + if (msgTextId) + { + MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(msgTextId), WASABI_API_LNGSTRINGW_BUF(IDS_CD_RIP,title,32), 0); + return ; + } + + if (m_dtracks && !m_atracks) + { + MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_ERROR_CANNOT_EXTRACT_DATA_CDS), + WASABI_API_LNGSTRINGW_BUF(IDS_CD_RIP,title,32), 0); + return ; + } + + l = (hwndList) ? ListView_GetItemCount(hwndList) : 0; + if (l) + { + p = (cdrip_params *)calloc(1, sizeof(cdrip_params)); + if (!p) return; + p->ntracks = l; + p->tracks = (wchar_t **)calloc(sizeof(wchar_t*), p->ntracks); + p->trackArtists = (wchar_t **)calloc(sizeof(wchar_t*), p->ntracks); + p->composers = (wchar_t **)calloc(sizeof(wchar_t*), p->ntracks); + p->gracenoteFileIDs = (wchar_t **)calloc(sizeof(wchar_t*), p->ntracks); + p->gracenoteExtData = (wchar_t **)calloc(sizeof(wchar_t*), p->ntracks); + p->conductors = (wchar_t **)calloc(sizeof(wchar_t*), p->ntracks); + p->lengths = (int *)calloc(sizeof(int), p->ntracks); + } + else p = NULL; + + lvitem.mask = LVIF_TEXT; + lvitem.iSubItem = 3; + lvitem.cchTextMax = sizeof(buf)/sizeof(char); + + for (i = 0;i < l;i++) + { + if (all || (LVIS_SELECTED & ListView_GetItemState(hwndList, i, LVIS_SELECTED))) + { + wchar_t cdFilename[MAX_PATH] = {0}; + StringCchPrintfW(cdFilename, MAX_PATH, L"cda://%c,%d.cda", cLetter, i + 1); + //check if track is Data track + { + wchar_t buf2[512] = L""; + getFileInfoW(cdFilename, L"tracktype", buf2, sizeof(buf2)/sizeof(*buf2)); + if (lstrcmpiW(buf2, L"audio")) continue; //skip it + } + + lvitem.iItem = i; + lvitem.pszText = buf; + SendMessageW(hwndList, LVM_GETITEMTEXTW, i, (LPARAM)&lvitem); + int len = _wtoi(lvitem.pszText) * 60 + _wtoi(wcsstr(lvitem.pszText, L":") + 1); //such hackish :) + + p->total_length_bytes += len * 44100 * 4; + + getFileInfoW(cdFilename, L"title", info, sizeof(info)/sizeof(wchar_t)); + p->tracks[i] = _wcsdup(info); + + getFileInfoW(cdFilename, L"artist", info, sizeof(info)/sizeof(wchar_t)); + p->trackArtists[i] = _wcsdup(info); + + getFileInfoW(cdFilename, L"composer", info, sizeof(info)/sizeof(wchar_t)); + p->composers[i] = _wcsdup(info); + + getFileInfoW(cdFilename, L"conductor", info, sizeof(info)/sizeof(wchar_t)); + p->conductors[i] = _wcsdup(info); + + getFileInfoW(cdFilename, L"GracenoteFileID", info, sizeof(info)/sizeof(wchar_t)); + p->gracenoteFileIDs[i] = _wcsdup(info); + + getFileInfoW(cdFilename, L"GracenoteExtData", info, sizeof(info)/sizeof(wchar_t)); + p->gracenoteExtData[i] = _wcsdup(info); + + p->lengths[i] = len; + cnt++; + } + } + if (!cnt) + { + if (p) + { + for (int i = 0 ; i < l; i ++) free(p->tracks[i]); + free(p->tracks); + free(p->trackArtists); + free(p->composers); + free(p->gracenoteFileIDs); + free(p->gracenoteExtData); + free(p->conductors); + free(p->lengths); + free(p); + } + MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_NO_TRACKS_TO_RIP), + WASABI_API_LNGSTRINGW_BUF(IDS_CD_RIP,title,32), MB_OK); + return ; + } + + p->filenames = (wchar_t **)calloc(sizeof(wchar_t *), p->ntracks); // allocate for cdrip to use :) + p->tempFilenames = (wchar_t **)calloc(sizeof(wchar_t *), p->ntracks); // allocate for cdrip to use :) + p->artist = _wcsdup(m_artist); + p->album = _wcsdup(m_album); + p->genre = _wcsdup(m_genre); + p->year = _wcsdup(m_year); + + wchar_t name[] = L"cda://X.cda"; + name[6] = cLetter; + + info[0] = 0; + getFileInfoW(name, L"publisher", info, sizeof(info)/sizeof(wchar_t)); + p->publisher = _wcsdup(info); + + info[0] = 0; + getFileInfoW(name, L"comment", info, sizeof(info)/sizeof(wchar_t)); + CopyComment(p->comment, info); + + info[0] = 0; + getFileInfoW(name, L"disc", info, sizeof(info)/sizeof(wchar_t)); + p->disc = _wcsdup(info); + + p->drive_letter = cLetter; + + cdrip_extractFiles(p); // will free p when done with it +} + +static void playFiles(HWND hwndDlg, CHAR cLetter, int enqueue, int all) +{ + HWND hwndList; + hwndList = GetDlgItem(hwndDlg, IDC_LIST2); + CHAR cMode; + INT msgTextId; + + cMode = DriveManager_GetDriveMode(cLetter); + + switch (cMode) + { + case DM_MODE_BURNING: msgTextId = IDS_ERROR_CD_RIP_IN_PROGRESS; break; + case DM_MODE_RIPPING: msgTextId = IDS_ERROR_CD_BURN_IN_PROGRESS; break; + default: msgTextId = 0; break; + } + if (msgTextId) + { + wchar_t title[64] = {0}; + MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(msgTextId), + WASABI_API_LNGSTRINGW_BUF(IDS_CD_PLAYBACK_ERROR, title, 64), 0); + return ; + } + + int cnt = 0; + int l = (hwndList) ? ListView_GetItemCount(hwndList) : 0; + if (enqueue && all == 1024) all = 0; + + int firstsel = -1; + char buf[64] = {0}, titlebuf[2048] = {0}; + enqueueFileWithMetaStruct s; + LVITEMA lvitem = {0}; + + lvitem.cchTextMax = sizeof(buf)/sizeof(char); + + for (int i = 0;i < l;i++) + { + if (all == 1024 && firstsel < 0 && (LVIS_SELECTED & ListView_GetItemState(hwndList, i, LVIS_SELECTED))) firstsel = i; + + if (all || (LVIS_SELECTED & ListView_GetItemState(hwndList, i, LVIS_SELECTED))) + { + lvitem.iItem = i; + + lvitem.mask = LVIF_PARAM; + lvitem.iSubItem = 0; + SendMessageW(hwndList, LVM_GETITEMA, 0, (LPARAM)&lvitem); + int a = (INT)(INT_PTR)lvitem.lParam; + if (a > 0) + { + if (!cnt) + { + if (!enqueue) SendMessageW(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_DELETE); + cnt++; + } + + lvitem.mask = LVIF_TEXT; + lvitem.iSubItem = 3; + lvitem.pszText = buf; + SendMessageW(hwndList, LVM_GETITEMTEXTA, i, (LPARAM)&lvitem); + + s.length = atoi(lvitem.pszText) * 60 + atoi(strstr(lvitem.pszText, ":") + 1); //such hackish :) + + StringCchPrintfA(buf, 64, "cda://%c,%d.cda", cLetter, i + 1); + TAG_FMT(0, 0, buf, titlebuf, sizeof(titlebuf)/sizeof(*titlebuf)); + s.filename = buf; + s.title = titlebuf; + s.ext = NULL; + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILE); + } + } + } + if (cnt && !enqueue) + { + if (firstsel >= 0) + { + SendMessage(plugin.hwndWinampParent, WM_WA_IPC, firstsel, IPC_SETPLAYLISTPOS); + SendMessage(plugin.hwndWinampParent, WM_COMMAND, 40047, 0); // stop button, literally + SendMessage(plugin.hwndWinampParent, WM_COMMAND, 40045, 0); // play button, literally + } + else SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_STARTPLAY); + } +} + +void saveCDToItemRecordList(CHAR cLetter, itemRecordList *obj, char *albumname) +{ + char fname[64] = {0}, buf2[64] = {0}; + StringCchPrintfA(fname, 64, "cda://%c.cda", cLetter); + + getFileInfo(fname, "<begin>", buf2, sizeof(buf2)/sizeof(char)); + getFileInfo(fname, "ntracks", buf2, sizeof(buf2)/sizeof(char)); + + int ntracks = atoi(buf2); + + if (ntracks > 0 && ntracks < 256) + { + obj->Items = 0; obj->Alloc = 0; obj->Size = 0; + allocRecordList(obj, ntracks, 0); + + int x; + for (x = 0; x < ntracks; x ++) + { + StringCchPrintfA(fname, 64, "cda://%c,%d.cda", cLetter, x + 1); + getFileInfo(fname, "tracktype", buf2, sizeof(buf2)/sizeof(char)); + if (!lstrcmpiA(buf2, "audio")) + { + int len = -1; + char titlebuf[FILETITLE_SIZE] = {0}; + mediaLibrary.GetFileInfo(fname, titlebuf, FILETITLE_SIZE, &len); + itemRecord *pRec = &obj->Items[obj->Size]; + ZeroMemory(pRec, sizeof(itemRecord)); + if (titlebuf) pRec->title = _strdup(titlebuf); + pRec->length = len; + if (fname) pRec->filename = _strdup(fname); + obj->Size++; + } + } + } + getFileInfo(fname, "<end>", buf2, sizeof(buf2)/sizeof(char)); +} + + + + +static ChildWndResizeItem cdromwnd_rlist[] = +{ + {IDC_LIST2, 0x0011}, + {IDC_CDINFO, 0x0000}, + {IDC_CDINFO2, 0x0000}, + {IDC_BUTTON_PLAY, 0x0101}, + {IDC_BUTTON_ENQUEUE, 0x0101}, + {IDC_BUTTON_EXTRACT, 0x0101}, + {IDC_BUTTON_EJECT, 0x0101}, + {IDC_BTN_SHOWINFO, 0x1111}, +}; + +typedef struct _VIEWCOLUMN +{ + INT stringId; + LPTSTR pszConfig; + INT defaultWidth; +} VIEWCOLUMN; + +static VIEWCOLUMN viewColumns[] = +{ + { IDS_TRACK_NUMBER, TEXT("col_track"), 60 }, + { IDS_ARTIST, TEXT("col_artist"), 150 }, + { IDS_TITLE, TEXT("col_title"), 200 }, + { IDS_LENGTH, TEXT("col_len"), 80 }, +}; + +static char m_cdrom; + +typedef struct _APCPARAM +{ + HWND hwndDlg; + CHAR cLetter; + INT_PTR user; +} +APCPARAM; + +static void CALLBACK APC_GetCracenoteInfo(ULONG_PTR param); + +static void GetGracenoteInfo(HWND hwndDlg, CHAR cLetter, HANDLE hThread = NULL) +{ + HWND hwndList; + int l, x; + LVITEMW lvitem = {0}; + wchar_t buf[32] = {0}, titlebuf[256] = {0}; + + if (hThread) + { + APCPARAM *pParam = (APCPARAM*)calloc(1, sizeof(APCPARAM)); + if (pParam) + { + pParam->cLetter = cLetter; + pParam->hwndDlg = hwndDlg; + if (!QueueUserAPC(APC_GetCracenoteInfo, hThread, (ULONG_PTR)pParam)) free(pParam); + } + return; + } + + hwndList = GetDlgItem(hwndDlg, IDC_LIST2); + if (!hwndList) return; + + l = (INT)SendMessageW(hwndList, LVM_GETITEMCOUNT, 0,0); + + // first, let's try to get artist/album info + { + StringCchPrintfW(buf, 32, L"cda://%c.cda", cLetter); + wchar_t artistbuf[256] = {0}, albumbuf[256] = {0}, yearbuf[256] = {0}, genrebuf[256] = {0}; + getFileInfoW(buf, L"albumartist", artistbuf, sizeof(artistbuf) / sizeof(artistbuf[0])); + getFileInfoW(buf, L"album", albumbuf, sizeof(albumbuf) / sizeof(albumbuf[0])); + getFileInfoW(buf, L"genre", genrebuf, sizeof(genrebuf) / sizeof(genrebuf[0])); + getFileInfoW(buf, L"year", yearbuf, sizeof(yearbuf) / sizeof(yearbuf[0])); + + wchar_t newbuf[1024] = {0}; + lstrcpynW(m_artist, artistbuf, sizeof(m_artist)/sizeof(*m_artist)); + lstrcpynW(m_album, albumbuf, sizeof(m_album)/sizeof(*m_album)); + lstrcpynW(m_year, yearbuf, sizeof(m_year)/sizeof(*m_year)); + lstrcpynW(m_genre, genrebuf, sizeof(m_genre)/sizeof(*m_genre)); + StringCchPrintfW(newbuf, 1024, WASABI_API_LNGSTRINGW(IDS_ML_VIEW_ARTIST_ALBUM), artistbuf, albumbuf); + SetDlgItemText(hwndDlg, IDC_CDINFO, newbuf); + StringCchPrintfW(newbuf, 1024, WASABI_API_LNGSTRINGW(IDS_ML_VIEW_YEAR_GENRE), yearbuf, genrebuf); + SetDlgItemText(hwndDlg, IDC_CDINFO2, newbuf); + } + + for (x = 0; x < l; x ++) + { + lvitem.iItem = x; + lvitem.mask = LVIF_PARAM; + lvitem.iSubItem = 0; + SendMessageW(hwndList, LVM_GETITEMW, 0, (LPARAM)&lvitem); + + int wt = (INT)(INT_PTR)lvitem.lParam; + + if (wt > 0) + { + StringCchPrintfW(buf, 32, L"cda://%c,%d.cda", cLetter, x + 1); + + lvitem.mask = LVIF_TEXT; + + titlebuf[0] = 0; + getFileInfoW(buf, L"title", titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0])); + if (titlebuf[0]) + { + lvitem.iSubItem = 2; + lvitem.pszText = titlebuf; + SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&lvitem); + } + + titlebuf[0] = 0; + getFileInfoW(buf, L"artist", titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0])); + if (titlebuf[0]) + { + lvitem.iSubItem = 1; + lvitem.pszText = titlebuf; + SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&lvitem); + } + } + } + + if (l && hwndList) + UpdateWindow(hwndList); + + if ( Plugin_IsExtractScheduled( cLetter ) ) + extractFiles( hwndDlg, cLetter, 1 ); +} + +static void UpdateCDView(HWND hwndDlg, DM_NOTIFY_PARAM *phdr) +{ + HWND hwndList; + + m_cdrom = phdr->cLetter; + m_atracks = m_dtracks = 0; + + hwndList = GetDlgItem(hwndDlg, IDC_LIST2); + if (!hwndList) return; + + ListView_DeleteAllItems(hwndList); + + SetDlgItemText(hwndDlg, IDC_CDINFO2, L""); + + SendMessageW(hwndList, WM_SETREDRAW, FALSE, 0L); + + if (DMOP_MCIINFO == phdr->opCode) + { + DM_MCI_PARAM *pmci; + LVITEMW lvitem = {0}; + wchar_t buffer[512] = {0}; + INT strid, param; + pmci = (DM_MCI_PARAM*)phdr; + + for (int i = 0; i < pmci->nTracks; i++) + { + INT time = (0x7FFFFFFF & pmci->pTracks[i])/1000; + + if (0x80000000 & pmci->pTracks[i]) + { + param = i + 1; strid = IDS_AUDIO_TRACK; m_atracks++; + } + else + { + param = -1; strid = IDS_DATA_TRACK; m_dtracks++; + } + + StringCchPrintfW(buffer, sizeof(buffer)/sizeof(wchar_t), L"%d", i + 1); + + lvitem.mask = LVIF_TEXT | LVIF_PARAM; + lvitem.iItem = i; + lvitem.iSubItem = 0; + lvitem.pszText = buffer; + lvitem.lParam = param; + INT index = (INT)SendMessageW(hwndList, LVM_INSERTITEMW, 0, (LPARAM)&lvitem); + + if (-1 != index) + { + lvitem.iItem = index; + lvitem.mask = LVIF_TEXT; + + lvitem.iSubItem = 2; + lvitem.pszText = WASABI_API_LNGSTRINGW(strid); + SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&lvitem); + + if (time < 0) StringCchCopyW(buffer, sizeof(buffer)/sizeof(wchar_t), L"???"); + else StringCchPrintfW(buffer, sizeof(buffer)/sizeof(wchar_t), L"%d:%02d", time / 60, time % 60); + + lvitem.iSubItem = 3; + lvitem.pszText = buffer; + SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&lvitem); + } + } + + SetDlgItemText(hwndDlg, IDC_CDINFO, WASABI_API_LNGSTRINGW((m_atracks) ? IDS_CD_AUDIO : ((m_dtracks) ? IDS_DATA_CD : IDS_NO_CD))); + + if (m_atracks) GetGracenoteInfo(hwndDlg, phdr->cLetter, GetCurrentThread()); + } + else SetDlgItemText(hwndDlg, IDC_CDINFO, WASABI_API_LNGSTRINGW(IDS_NO_CD)); + + SendMessageW(hwndList, WM_SETREDRAW, TRUE, 0L); + UpdateWindow(hwndList); +} + +static LRESULT editCDInfo(HWND hwndDlg, CHAR cLetter, int trackNum) +{ + wchar_t name[MAX_PATH] = {0}; + if (trackNum) + StringCchPrintfW(name, MAX_PATH, L"cda://%c,%d", cLetter, trackNum); + else + StringCchPrintfW(name, MAX_PATH, L"cda://%c.cda", cLetter); + infoBoxParamW p; + p.filename = name; + p.parent = hwndDlg; + return SendMessageW(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&p, IPC_INFOBOXW); +} + +static void NotifyInfoWindow(HWND hwnd, CHAR cLetter, INT nTrack, BOOL bForceRefresh) +{ + HWND hwndParent; + hwndParent = GetParent(hwnd); + + if (hwndParent) + { + wchar_t szFileName[MAX_PATH], *p; + if (nTrack && S_OK == StringCchPrintfW(szFileName, sizeof(szFileName)/sizeof(wchar_t), L"cda://%c,%d.cda", cLetter, nTrack)) p = szFileName; + else p = L""; + SendMessageW(hwndParent, WM_SHOWFILEINFO, (WPARAM)((bForceRefresh) ? WISF_FORCE : WISF_NORMAL), (LPARAM)p); + } +} + +static BOOL Window_OnInitDialog(HWND hwndDlg, HWND hwndFocus, LPARAM lParam) +{ + HWND hwndList; + + if (!lParam) + { + DestroyWindow(hwndDlg); + return 0; + } + + SendMessageW(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(IDC_BTN_SHOWINFO, BN_EX_GETTEXT), (LPARAM)GetDlgItem(hwndDlg, IDC_BTN_SHOWINFO)); + + childSizer.Init(hwndDlg, cdromwnd_rlist, sizeof(cdromwnd_rlist) / sizeof(cdromwnd_rlist[0])); + + hwndList = GetDlgItem(hwndDlg, IDC_LIST2); + + if (hwndList) + { + MLSKINWINDOW sw; + LVCOLUMNW column; + + sw.hwndToSkin = hwndList; + sw.skinType = SKINNEDWND_TYPE_LISTVIEW; + sw.style = SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS | SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS; + MLSkinWindow(plugin.hwndLibraryParent, &sw); + + column.mask = LVCF_WIDTH | LVCF_TEXT; + for (int i = 0; i < sizeof(viewColumns)/sizeof(VIEWCOLUMN); i++) + { + column.cx = g_view_metaconf->ReadInt(viewColumns[i].pszConfig, viewColumns[i].defaultWidth); + column.pszText = WASABI_API_LNGSTRINGW(viewColumns[i].stringId); + SendMessageW(hwndList, LVM_INSERTCOLUMNW, (WPARAM)0xEFFF, (LPARAM)&column); + } + } + + + SetDlgItemText(hwndDlg, IDC_CDINFO, L""); + SetDlgItemText(hwndDlg, IDC_CDINFO2, L""); + + NotifyInfoWindow(hwndDlg, ((DM_NOTIFY_PARAM*)lParam)->cLetter, NULL, TRUE); // ignore cache + + UpdateCDView(hwndDlg, (DM_NOTIFY_PARAM*)lParam); + + return FALSE; +} +static void Window_OnDestroy(HWND hwndDlg) +{ + HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST2); + + if (hwndList) + { + for (int i = 0; i < sizeof(viewColumns)/sizeof(VIEWCOLUMN); i++) + { + g_view_metaconf->WriteInt(viewColumns[i].pszConfig, + (INT)SendMessageW(hwndList, LVM_GETCOLUMNWIDTH, i, 0L)); + } + } + + if (m_cdrom) NotifyInfoWindow(hwndDlg, m_cdrom, NULL, FALSE); + +} + + +static void Window_OnSize(HWND hwndDlg, UINT nType, INT cx, INT cy) +{ + if (nType != SIZE_MINIMIZED) + { + childSizer.Resize(hwndDlg, cdromwnd_rlist, sizeof(cdromwnd_rlist) / sizeof(cdromwnd_rlist[0])); + InvalidateRect(hwndDlg, NULL, TRUE); + } +} + +static void CALLBACK Window_TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + HWND hwndList; + + switch (idEvent) + { + case TIMER_NOTIFYINFO_ID: + KillTimer(hwnd, TIMER_NOTIFYINFO_ID); + hwndList = GetDlgItem(hwnd, IDC_LIST2); + NotifyInfoWindow(hwnd, m_cdrom, + (hwndList) ? (INT)SendMessage(hwndList, LVM_GETNEXTITEM, (WPARAM)-1, (LPARAM)LVNI_FOCUSED) + 1: 0, + FALSE); + break; + } +} + +static void Window_OnCommand(HWND hwndDlg, INT eventId, INT ctrlId, HWND hwndCtrl) +{ + switch (ctrlId) + { + case IDC_BUTTON_ENQUEUE: + case IDC_BUTTON_PLAY: + { + HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST2); + if (hwndList) + { + int selcnt = (INT)SendMessageW(hwndList, LVM_GETSELECTEDCOUNT, 0, 0L); + playFiles(hwndDlg, m_cdrom, (IDC_BUTTON_ENQUEUE == ctrlId), (selcnt) ? ((selcnt == 1) ? 1024 : 0) : 1); + } + } + break; + case IDC_BUTTON_EXTRACT: + { + RECT r; + GetWindowRect(hwndCtrl, &r); + int x = Menu_TrackPopup(plugin.hwndLibraryParent, GetSubMenu(g_context_menus, 0), + TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_BOTTOMALIGN | + TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RETURNCMD, + r.left, r.top, hwndDlg, NULL); + switch (x) + { + case ID_EXTRACTMENU_EXTRACTSELECTEDTRACKS: extractFiles(hwndDlg, m_cdrom, 0); break; + case ID_EXTRACTMENU_EXTRACTALLTRACKS: extractFiles(hwndDlg, m_cdrom, 1); break; + case ID_EXTRACTMENU_CONFIGURE: Plugin_ShowRippingPreferences(); break; + } + UpdateWindow(hwndDlg); + Sleep(100); + MSG msg; + while (PeekMessageW(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); //eat return + } + break; + case IDC_BUTTON_EJECT: + { + wchar_t result[32] = {0}; + wchar_t name[] = L"cda://X.cda"; + + name[6] = m_cdrom; + getFileInfoW(name, L"<eject>", result, sizeof(result)/sizeof(wchar_t)); + } + break; + case IDC_BTN_SHOWINFO: + switch (eventId) + { + case BN_CLICKED: + SendMessageW(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(ctrlId, eventId), (LPARAM)hwndCtrl); + break; + } + break; + } +} +static void ListView_OnItemChanged(HWND hwndDlg, NMLISTVIEW *pnmv) +{ + if (LVIF_STATE & pnmv->uChanged) + { + if ((LVIS_FOCUSED & pnmv->uOldState) != (LVIS_FOCUSED & pnmv->uNewState)) + { + KillTimer(hwndDlg, TIMER_NOTIFYINFO_ID); + SetTimer(hwndDlg, TIMER_NOTIFYINFO_ID, TIMER_NOTIFYINFO_DELAY, Window_TimerProc); + + } + } +} +static INT_PTR Window_OnNotify(HWND hwndDlg, INT ctrlId, LPNMHDR phdr) +{ + switch (phdr->idFrom) + { + case IDC_LIST2: + switch (phdr->code) + { + case LVN_ITEMCHANGED: ListView_OnItemChanged(hwndDlg, (NMLISTVIEW*)phdr); break; + case LVN_KEYDOWN: + { + LPNMLVKEYDOWN pnkd = (LPNMLVKEYDOWN)phdr; + switch (pnkd->wVKey) + { + case '3': + if (GetAsyncKeyState(VK_MENU)&0x8000) + { + W_ListView view(GetDlgItem(hwndDlg, IDC_LIST2)); + if (view.GetSelectedCount() == 0 || view.GetSelectedCount() == view.GetCount()) + editCDInfo(hwndDlg, m_cdrom, 0); + + int sel =-1; + while ((sel = view.GetNextSelected(sel)) != -1) + { + if (editCDInfo(hwndDlg, m_cdrom, sel+1) == 1) + break; + } + + + PostMessageW(hwndDlg, WM_NEXTDLGCTL, (WPARAM)phdr->hwndFrom, TRUE); + } + break; + case 'A': + if (GetAsyncKeyState(VK_CONTROL)) ListView_SetItemState(phdr->hwndFrom, -1, LVIS_SELECTED, LVIS_SELECTED); + break; + } + } + break; + case NM_DBLCLK: + playFiles(hwndDlg, m_cdrom, (!!g_config->ReadInt(L"enqueuedef", 0)) ^(!!(GetAsyncKeyState(VK_SHIFT)&0x8000)), 1024); + break; + case LVN_BEGINDRAG: + SetCapture(hwndDlg); + break; + case NM_RETURN: + SendMessageW(hwndDlg, WM_COMMAND, ((!!(GetAsyncKeyState(VK_SHIFT)&0x8000)) ^(!!g_config->ReadInt(L"enqueuedef", 0))) + ? IDC_BUTTON_ENQUEUE : IDC_BUTTON_PLAY, 0); + break; + } + break; + } + return 0; +} + +static void Window_OnMouseMove(HWND hwndDlg, INT vKey, POINTS pts) +{ + mlDropItemStruct m = {0}; + if (GetCapture() != hwndDlg) return; + + POINTSTOPOINT(m.p, pts); + MapWindowPoints(hwndDlg, HWND_DESKTOP, &m.p, 1); + + m.type = ML_TYPE_CDTRACKS; + + SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_HANDLEDRAG, (WPARAM)&m); + +} + +static void Window_OnLButtonUp(HWND hwndDlg, INT vKey, POINTS pts) +{ + mlDropItemStruct m = {0}; + + if (GetCapture() != hwndDlg) return; + + ReleaseCapture(); + + m.type = ML_TYPE_CDTRACKS; + m.flags = ML_HANDLEDRAG_FLAG_NOCURSOR; + + POINTSTOPOINT(m.p, pts); + MapWindowPoints(hwndDlg, HWND_DESKTOP, &m.p, 1); + + SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_HANDLEDRAG, (WPARAM)&m); + + if (m.result > 0) + { + HWND hwndList; + LVITEMW lvitem = {0}; + int i, l, len; + itemRecordList myObj = {0}; + char trackname[] = "cda://X,%d.cda"; + char name[32] = {0}, total[512] = {0}; + + hwndList = GetDlgItem(hwndDlg, IDC_LIST2); + + l = (hwndList) ? (INT)SendMessageW(hwndList, LVM_GETITEMCOUNT, 0,0) : 0; + if (l > 256) l = 256; + + + allocRecordList(&myObj, l, 0); + + lvitem.mask = LVIF_PARAM; + lvitem.iSubItem = 0; + + trackname[6] = m_cdrom; + + for (i = 0; i < l; i++) + { + lvitem.iItem = i; + SendMessageW(hwndList, LVM_GETITEMW, 0, (LPARAM)&lvitem); + int p = (INT)(INT_PTR)lvitem.lParam; + + if ((LVIS_SELECTED & SendMessageW(hwndList, LVM_GETITEMSTATE, i, LVIS_SELECTED)) && p > 0) + { + + StringCchPrintfA(name, sizeof(name)/sizeof(char), trackname, p); + + total[0] = 0; + mediaLibrary.GetFileInfo(name, total, sizeof(total)/sizeof(char), &len); + memset(myObj.Items + myObj.Size, 0, sizeof(itemRecord)); + myObj.Items[myObj.Size].filename = _strdup(name); + myObj.Items[myObj.Size].length = len; + myObj.Items[myObj.Size++].title = _strdup(total); + } + } + if (myObj.Size) + { + m.flags = 0; + m.result = 0; + m.data = (void*)&myObj; + SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_HANDLEDROP, (WPARAM)&m); + } + + freeRecordList(&myObj); + } +} + + + +static void Window_OnQueryInfo(HWND hwnd) +{ + KillTimer(hwnd, TIMER_NOTIFYINFO_ID); + NotifyInfoWindow(hwnd, m_cdrom, NULL, TRUE); + SetTimer(hwnd, TIMER_NOTIFYINFO_ID, TIMER_NOTIFYINFO_DELAY, Window_TimerProc); +} + + +static void Window_OnFileTagUpdated(HWND hwnd, CHAR cLetter, LPCWSTR pszFileName) +{ + INT len, lcid; + + len = (pszFileName) ? lstrlenW(pszFileName) : 0; + if (len < 7) return; + lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); + if (CSTR_EQUAL == CompareStringW(lcid, 0, L"cda://", 6, pszFileName, 6) && pszFileName[6] == cLetter) + { + GetGracenoteInfo(hwnd, cLetter, GetCurrentThread()); + } +} + +static void Window_OnContextMenu(HWND hwndDlg, HWND hwndFrom, int x, int y) +{ + POINT pt = {x,y}; + W_ListView view(GetDlgItem(hwndDlg, IDC_LIST2)); + + if(view.GetCount() == 0) return; + + if (x == -1 || y == -1) // x and y are -1 if the user invoked a shift-f10 popup menu + { + RECT itemRect = {0}; + int selected = view.GetNextSelected(); + if (selected != -1) // if something is selected we'll drop the menu from there + { + view.GetItemRect(selected, &itemRect); + ClientToScreen(view.getwnd(), (POINT *)&itemRect); + } + else // otherwise we'll drop it from the top-left corner of the listview, adjusting for the header location + { + GetWindowRect(view.getwnd(), &itemRect); + + HWND hHeader = (HWND)SNDMSG(hwndFrom, LVM_GETHEADER, 0, 0L); + RECT headerRect; + if ((WS_VISIBLE & GetWindowLongPtr(hHeader, GWL_STYLE)) && GetWindowRect(hHeader, &headerRect)) + { + itemRect.top += (headerRect.bottom - headerRect.top); + } + } + x = itemRect.left; + y = itemRect.top; + } + + HWND hHeader = (HWND)SNDMSG(hwndFrom, LVM_GETHEADER, 0, 0L); + RECT headerRect; + if (0 == (WS_VISIBLE & GetWindowLongPtr(hHeader, GWL_STYLE)) || FALSE == GetWindowRect(hHeader, &headerRect)) + { + SetRectEmpty(&headerRect); + } + + if (FALSE != PtInRect(&headerRect, pt)) + { + return; + } + + int r = Menu_TrackPopup(plugin.hwndLibraryParent, GetSubMenu(g_context_menus, 1), + TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_NONOTIFY, + x, y, hwndDlg, NULL); + switch (r) + { + case ID_PE_ID3: + { + if (view.GetSelectedCount() == 0 || view.GetSelectedCount() == view.GetCount()) + editCDInfo(hwndDlg, m_cdrom, 0); + + int sel =-1; + while ((sel = view.GetNextSelected(sel)) != -1) + { + if (editCDInfo(hwndDlg, m_cdrom, sel+1) == 1) + break; + } + } + PostMessageW(hwndDlg, WM_NEXTDLGCTL, (WPARAM)hwndFrom, TRUE); + break; + case ID_CDROMMENU_PLAYSELECTEDITEMS: playFiles(hwndDlg, m_cdrom, 0, 0); break; + case ID_CDROMMENU_ENQUEUESELECTEDITEMS: playFiles(hwndDlg, m_cdrom, 1, 0); break; + case ID_CDROMMENU_SELECTALL: ListView_SetItemState(hwndFrom, -1, LVIS_SELECTED, LVIS_SELECTED); break; + case ID_CDROMMENU_PLAYALL: playFiles(hwndDlg, m_cdrom, 0, 1); break; + case ID_CDROMMENU_ENQUEUEALL: playFiles(hwndDlg, m_cdrom, 1, 1); break; + case ID_CDROMMENU_EXTRACT_EXTRACTSELECTEDITEMS: extractFiles(hwndDlg, m_cdrom, 0); break; + case ID_CDROMMENU_EXTRACT_EXTRACTALL: extractFiles(hwndDlg, m_cdrom, 1); break; + case ID_CDROMMENU_EXTRACT_CONFIGURE: Plugin_ShowRippingPreferences(); break; + } + UpdateWindow(hwndDlg); + Sleep(100); + MSG msg; + while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); //eat return +} + +static INT_PTR WINAPI DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + INT_PTR a; + a = dialogSkinner.Handle(hwndDlg, uMsg, wParam, lParam); + if (a) return a; + + switch (uMsg) + { + case WM_INITDIALOG: return Window_OnInitDialog(hwndDlg, (HWND)wParam, lParam); + case WM_DESTROY: Window_OnDestroy(hwndDlg); break; + case WM_SIZE: Window_OnSize(hwndDlg, (UINT)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(wParam)); break; + case WM_COMMAND: Window_OnCommand(hwndDlg, HIWORD(wParam), LOWORD(wParam), (HWND)lParam); break; + case WM_NOTIFY: return Window_OnNotify(hwndDlg, (INT)wParam, (LPNMHDR) lParam); + case WM_MOUSEMOVE: Window_OnMouseMove(hwndDlg, (INT)wParam, MAKEPOINTS(lParam)); break; + case WM_LBUTTONUP: Window_OnLButtonUp(hwndDlg, (INT)wParam, MAKEPOINTS(lParam)); break; + case WM_CONTEXTMENU: Window_OnContextMenu(hwndDlg, (HWND)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return 1; + case WM_ERASEBKGND: return 1; + case WM_TAGUPDATED: Window_OnFileTagUpdated(hwndDlg, m_cdrom, (LPCWSTR)lParam); break; + case WM_QUERYFILEINFO: Window_OnQueryInfo(hwndDlg); break; + case WM_PAINT: + { + int tab[] = { IDC_LIST2 | DCW_SUNKENBORDER}; + dialogSkinner.Draw(hwndDlg, tab, 1); + } + return 0; + + case WM_EXTRACTDISC: + if ((CHAR)wParam == m_cdrom) extractFiles(hwndDlg, m_cdrom, TRUE); + SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, ((CHAR)wParam == m_cdrom)); + return TRUE; + + } + + return 0; +} + +static void CALLBACK APC_GetCracenoteInfo(ULONG_PTR param) +{ + GetGracenoteInfo(((APCPARAM*)param)->hwndDlg, ((APCPARAM*)param)->cLetter, NULL); + free((APCPARAM*)param); +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/view_container.cpp b/Src/Plugins/Library/ml_disc/view_container.cpp new file mode 100644 index 00000000..d5dad335 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/view_container.cpp @@ -0,0 +1,573 @@ +#include "main.h" +#include "./resource.h" +#include "../nu/DialogSkinner.h" +#include "../nu/AutoWideFn.h" +#include "./commandbar.h" +#include "./settings.h" +#include "../nu/trace.h" + +//#include <primosdk.h> +#include <windowsx.h> +#include <strsafe.h> + +#define MINIINFO_HEIGHT 100 + +#define IDC_CHILDVIEW 0x1000 +#define IDC_MINIINFO 0x1001 +#define IDC_COMMAND_BAR 0x1002 + +#define WINDOWS_SPACING 3 + +#define CONTAINER_PROPW L"CONTAINER" + +typedef struct _CONTAINER +{ + CHAR cLetter; + INT typeChild; + BOOL bInfoVisible; + HANDLE hLastQuery; +} CONTAINER; + +static UINT msgNotify = 0; +#define GetContainer(__hwnd) ((CONTAINER*)GetPropW(__hwnd, CONTAINER_PROPW)) +static INT_PTR WINAPI DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +// public function +typedef struct _CONTAINER_PARAM +{ + CHAR cLetter; + BOOL bQueryInfo; +}CONTAINER_PARAM; + +HWND CreateContainerWindow(HWND hwndParent, CHAR cLetter, BOOL bQueryInfo) +{ + CONTAINER_PARAM param; + param.cLetter = cLetter; + param.bQueryInfo = bQueryInfo; + return WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_CONTAINER, hwndParent, DlgProc, (LPARAM)¶m); +} + +static void ViewContainer_LayoutChildren(HWND hdlg, BOOL bRedraw) +{ + RECT rc; + HWND hctrl; + HDWP hdwp; + DWORD flags; + + CONTAINER *pc = GetContainer(hdlg); + if (!pc) return; + + if (!GetClientRect(hdlg, &rc)) return; + rc.right -= 2; + + flags = SWP_NOACTIVATE | ((bRedraw) ? 0 : SWP_NOREDRAW); + + hdwp = BeginDeferWindowPos(3); + if (!hdwp) return; + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_COMMAND_BAR))) + { + INT height = CommandBar_GetBestHeight(hctrl); + hdwp = DeferWindowPos(hdwp, hctrl, HWND_BOTTOM, rc.left, rc.bottom - (height), rc.right - rc.left, height, flags); + rc.bottom -= (height + WINDOWS_SPACING); + } + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_MINIINFO)) && pc->bInfoVisible) + { + INT height = MINIINFO_HEIGHT; + hdwp = DeferWindowPos(hdwp, hctrl, HWND_TOP, rc.left, rc.bottom - height, rc.right - rc.left, height, flags); + rc.bottom -= (height + WINDOWS_SPACING); + } + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_CHILDVIEW))) + { + hdwp = DeferWindowPos(hdwp, hctrl, HWND_TOP, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, flags); + } + + EndDeferWindowPos(hdwp); +} + +static void CreateChild(HWND hParent, INT typeId, LPARAM param, BOOL fCreateAlways = TRUE) +{ + DM_NOTIFY_PARAM hdr; + CONTAINER *pc = GetContainer(hParent); + if (!pc) return; + + HWND hChild = GetDlgItem(hParent, IDC_CHILDVIEW); + if (hChild) + { + if (pc->typeChild == typeId && !fCreateAlways) return; + DestroyWindow(hChild); + } + + hChild = NULL; + pc->typeChild = 0; + + switch(typeId) + { + case IDD_VIEW_INFO: + hChild = CreateInfoWindow(hParent, (CHAR)(0xFF & param)); + break; + case IDD_VIEW_WAIT: + hChild = CreateWaitWindow(hParent, (CHAR)(0xFF & param)); + break; + case IDD_VIEW_CDROM: + if (param <= 0xFF) + { + ZeroMemory(&hdr, sizeof(DM_NOTIFY_PARAM)); + hdr.cLetter = (CHAR)(0xFF & (INT)param); + hdr.opCode = DMOP_GENERAL; + param = (INT_PTR)&hdr; + } + hChild = CreateCDViewWindow(hParent, (DM_NOTIFY_PARAM*)param); + break; + case IDD_VIEW_CDROM_EX2: + hChild = CreateCDRipWindow(hParent, (CHAR)(0xFF & param)); + break; + case IDD_VIEW_CDROM_DATA: + hChild = CreateCdDataViewWindow(hParent, (CHAR)(0xFF & param)); + break; + } + TRACE_FMT(L"Creating cd view (%d)\n", typeId); + if (hChild) + { + pc->typeChild = typeId; + SetWindowLongPtrW(hChild, GWLP_ID, IDC_CHILDVIEW); + ViewContainer_LayoutChildren(hParent, TRUE); + ShowWindow(hChild, SW_SHOWNA); + } +} + +static HWND CreateMiniInfoWindow(HWND hwndParent) +{ + RECT rw; + HWND hwnd; + WEBINFOCREATE wic; + + GetWindowRect(hwndParent, &rw); + + wic.hwndParent = hwndParent; + wic.uMsgQuery = WM_QUERYFILEINFO; + wic.ctrlId = IDC_MINIINFO; + wic.cx = rw.right - rw.left - 3; + wic.cy = MINIINFO_HEIGHT; + wic.x = 0; + wic.y = (rw.bottom - rw.top) - MINIINFO_HEIGHT - 1; + + hwnd = (HWND)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_CREATEWEBINFO, (WPARAM)&wic); + if (hwnd) + { + SetWindowLongPtrW(hwnd, GWL_EXSTYLE, GetWindowLongPtrW(hwnd, GWL_EXSTYLE) | WS_EX_CLIENTEDGE); + MLSkinWindow2(plugin.hwndLibraryParent, hwnd, SKINNEDWND_TYPE_WINDOW, SWS_USESKINCOLORS); + } + + return hwnd; +} + +static void CALLBACK FreeAsyncParam(DM_NOTIFY_PARAM *phdr) +{ + DM_MCI_PARAM *pmci; + switch(phdr->opCode) + { + case DMOP_MCIINFO: + pmci = (DM_MCI_PARAM*)phdr; + if (pmci->pTracks) free(pmci->pTracks); + break; + case DMOP_IMAPIINFO: + break; + } + free(phdr); +} + +static void QueryDriveRecordable(HWND hwnd, CHAR cLetter) +{ + CONTAINER *pc = GetContainer(hwnd); + if (!pc) return; + + DWORD dwType; + dwType = DriveManager_GetDriveType(cLetter); + if (0 == (DRIVE_CAP_UNKNOWN & dwType)) + { + CreateChild(hwnd, ((DRIVE_CAP_R | DRIVE_CAP_RW) & dwType) ? IDD_VIEW_CDROM_BURN : IDD_VIEW_CDROM, (LPARAM)cLetter); + return; + } + else + { + DM_UNITINFO_PARAM *pui; + + pui = (DM_UNITINFO_PARAM*)calloc(1, sizeof(DM_UNITINFO_PARAM)); + if (pui) + { + pui->header.callback = (INT_PTR)hwnd; + pui->header.uMsg = msgNotify; + pui->header.cLetter = cLetter; + pui->header.fnFree = FreeAsyncParam; + pc->hLastQuery = pui; + if (!DriveManager_GetUnitInfo(pui)) CreateChild(hwnd, IDD_VIEW_CDROM, (LPARAM)cLetter); + } + } +} + +static void QueryDiscInfo(HWND hwnd, CHAR cLetter) +{ + DM_MCI_PARAM *pmci; + CHAR cMode; + + CONTAINER *pc = GetContainer(hwnd); + if (!pc) return; + + cMode = DriveManager_GetDriveMode(cLetter); + + switch(cMode) + { + case DM_MODE_RIPPING: + if (cdrip_isextracting(cLetter)) CreateChild(hwnd, IDD_VIEW_CDROM_EX2, cLetter); + else CreateChild(hwnd, IDD_VIEW_INFO, cLetter); + return; + + case DM_MODE_COPYING: + if (IDD_VIEW_CDROM_DATA == pc->typeChild) return; + break; + case DM_MODE_READY: + if (IDD_VIEW_CDROM_DATA == pc->typeChild) return; + break; + } + + CreateChild(hwnd, IDD_VIEW_WAIT, cLetter); + + pmci = (DM_MCI_PARAM*)calloc(1, sizeof(DM_MCI_PARAM)); + if (pmci) + { + pmci->header.callback = (INT_PTR)hwnd; + pmci->header.uMsg = msgNotify; + pmci->header.cLetter = cLetter; + pmci->header.fnFree = FreeAsyncParam; + pmci->header.fFlags = DMF_READY | DMF_MEDIUMPRESENT | DMF_MODE | DMF_TRACKCOUNT | DMF_TRACKSINFO; + pmci->nTracks = 256; + pmci->pTracks = (DWORD*)calloc(pmci->nTracks, sizeof(DWORD)); + + pc->hLastQuery = pmci; + + if (!DriveManager_GetMCIInfo(pmci)) + { + pc->hLastQuery = NULL; + // display error dialog + } + } +} + +static void Medium_OnArrived(HWND hwnd, CHAR cLetter) +{ + QueryDiscInfo(hwnd, cLetter); +} + +static void Medium_OnRemoved(HWND hwnd, CHAR cLetter) +{ + QueryDriveRecordable(hwnd, cLetter); +} + +static void Drive_OnModeChanged(HWND hwnd, CHAR cLetter, CHAR cMode) +{ + QueryDiscInfo(hwnd, cLetter); + HWND hctrl = GetDlgItem(hwnd, IDC_CHILDVIEW); + if (hctrl) SendMessage(hctrl, WM_COMMAND, MAKEWPARAM(ID_DRIVE_MODE_CHANGED, 0), (LPARAM)hwnd); +} + +static void GetInfo_Completed(HWND hwnd, DM_NOTIFY_PARAM *phdr) +{ + DM_MCI_PARAM *pmci; + CONTAINER *pc = GetContainer(hwnd); + if (!pc || phdr != pc->hLastQuery) return; + + switch(phdr->opCode) + { + case DMOP_MCIINFO: + pmci = (DM_MCI_PARAM*)phdr; + if (0 == phdr->result) + { + if (pmci->bMediumPresent && pmci->nTracks > 0) + { + int i; + for (i = 0; i < pmci->nTracks; i++) if (0x80000000 & pmci->pTracks[i]) break; + if (i == pmci->nTracks) CreateChild(hwnd, IDD_VIEW_CDROM_DATA, (LPARAM)phdr->cLetter); + else CreateChild(hwnd, IDD_VIEW_CDROM, (LPARAM)phdr); + } + else QueryDriveRecordable(hwnd, phdr->cLetter); + } + else {/*go to error view*/ } + break; + case DMOP_UNITINFO: + CreateChild(hwnd, ( 0 == phdr->result && Drive_IsRecorderType(((DM_UNITINFO_PARAM*)phdr)->dwType)) ? IDD_VIEW_CDROM_BURN : IDD_VIEW_CDROM, (LPARAM)phdr->cLetter); + break; + } +} + +static BOOL ViewContainer_OnGetMiniInfoEnabled(HWND hdlg) +{ + return g_config->ReadInt(TEXT("useminiinfo2"), 0); +} + +static INT_PTR Window_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) +{ + CONTAINER_PARAM *param = (CONTAINER_PARAM*)lParam; + CONTAINER *pc = (CONTAINER*)calloc(1, sizeof(CONTAINER)); + if (pc) + { + pc->cLetter = param->cLetter; + SetPropW(hwnd, CONTAINER_PROPW, pc); + } + + MLSkinWindow2(plugin.hwndLibraryParent, hwnd, SKINNEDWND_TYPE_DIALOG, SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS); + + BOOL bVal = FALSE; + if (S_OK == Settings_GetBool(C_GLOBAL, GF_SHOWINFO, &bVal) && bVal) + SendMessageW(hwnd, WM_COMMAND, MAKEWPARAM(IDC_BTN_SHOWINFO, BN_CLICKED), (LPARAM)NULL); + + if (!msgNotify) msgNotify = RegisterWindowMessageW(L"cdrom_notify_msg"); + Plugin_RegisterListener(hwnd, msgNotify, pc->cLetter); + + if (param->bQueryInfo) QueryDiscInfo(hwnd, pc->cLetter); + + if (WASABI_API_APP) + { + HACCEL hAccel = WASABI_API_LOADACCELERATORSW(IDR_ACCELERATOR_VIEW); + if (hAccel) WASABI_API_APP->app_addAccelerators(hwnd, &hAccel, 1, TRANSLATE_MODE_CHILD); + WASABI_API_APP->ActiveDialog_Register(hwnd); + } + + return 0; +} + +static void Window_OnDestroy(HWND hdlg) +{ + Plugin_UnregisterListener(hdlg); + if (WASABI_API_APP) WASABI_API_APP->app_removeAccelerators(hdlg); + + HWND hctrl = GetDlgItem(hdlg, IDC_MINIINFO); + if (hctrl && IsWindow(hctrl)) SENDMLIPC(hctrl, ML_IPC_WEBINFO_RELEASE, 0); + + CONTAINER *pc = GetContainer(hdlg); + if (pc) + { + Settings_SetBool(C_GLOBAL, GF_SHOWINFO, pc->bInfoVisible); + RemovePropW(hdlg, CONTAINER_PROPW); + free(pc); + } +} + +static void Window_OnDisplayChange(HWND hdlg, INT dpi, INT resX, INT resY) +{ + SendDlgItemMessageW(hdlg, IDC_CHILDVIEW, WM_DISPLAYCHANGE, dpi, MAKELPARAM(resX, resY)); + SendDlgItemMessageW(hdlg, IDC_MINIINFO, WM_DISPLAYCHANGE, dpi, MAKELPARAM(resX, resY)); + SendDlgItemMessageW(hdlg, IDC_COMMAND_BAR, WM_DISPLAYCHANGE, dpi, MAKELPARAM(resX, resY)); +} + +static void ViewContainer_OnWindowPosChanged(HWND hdlg, WINDOWPOS *pwp) +{ + RECT rc, rw; + HWND hctrl; + HDWP hdwp; + DWORD flags; + + CONTAINER *pc = GetContainer(hdlg); + if (!pc) return; + + if (SWP_FRAMECHANGED & pwp->flags) + { + ViewContainer_LayoutChildren(hdlg, (SWP_NOREDRAW & pwp->flags)); + return; + } + + if (0 != (SWP_NOSIZE & pwp->flags)) return; + + if (!GetClientRect(hdlg, &rc)) return; + + rc.right -= 2; + + flags = SWP_NOACTIVATE | SWP_NOZORDER | ((SWP_NOREDRAW | SWP_NOCOPYBITS) & pwp->flags); + + hdwp = BeginDeferWindowPos(3); + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_COMMAND_BAR)) && GetWindowRect(hctrl, &rw)) + { + hdwp = DeferWindowPos(hdwp, hctrl, HWND_BOTTOM, rc.left, rc.bottom - (rw.bottom - rw.top), rc.right - rc.left, (rw.bottom - rw.top), flags); + rc.bottom -= (rw.bottom - rw.top + WINDOWS_SPACING); + } + + if (pc->bInfoVisible && NULL != (hctrl = GetDlgItem(hdlg, IDC_MINIINFO)) && GetWindowRect(hctrl, &rw)) + { + hdwp = DeferWindowPos(hdwp, hctrl, HWND_BOTTOM, rc.left, rc.bottom - (rw.bottom - rw.top), rc.right - rc.left, (rw.bottom - rw.top), flags); + rc.bottom -= (rw.bottom - rw.top + WINDOWS_SPACING); + } + + if (NULL != (hctrl = GetDlgItem(hdlg, IDC_CHILDVIEW))) + { + hdwp = DeferWindowPos(hdwp, hctrl, HWND_TOP, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, flags | SWP_NOMOVE); + } + + EndDeferWindowPos(hdwp); +} + +static void ViewContainer_ShowMiniInfo(HWND hdlg, BOOL bShow) +{ + CONTAINER *pc = GetContainer(hdlg); + if (!pc) return; + + pc->bInfoVisible = FALSE; + + HWND hInfo = GetDlgItem(hdlg, IDC_MINIINFO); + if (bShow && !hInfo) hInfo = CreateMiniInfoWindow(hdlg); + + if (hInfo) + { + if (bShow) + { + pc->bInfoVisible = TRUE; + ViewContainer_LayoutChildren(hdlg, TRUE); + ShowWindow(hInfo, SW_SHOWNA); + UpdateWindow(hInfo); + } + else + { + ShowWindow(hInfo, SW_HIDE); + ViewContainer_LayoutChildren(hdlg, TRUE); + } + } + + HWND hctrl = GetDlgItem(hdlg, IDC_CHILDVIEW); + if (hctrl && NULL != (hctrl = GetDlgItem(hctrl, IDC_BTN_SHOWINFO))) + SetWindowTextW(hctrl, WASABI_API_LNGSTRINGW((bShow) ? IDS_HIDE_INFO : IDS_SHOW_INFO)); +} + +static void Window_OnCommand(HWND hdlg, INT eventId, INT ctrlId, HWND hctrl) +{ + CONTAINER *pc = GetContainer(hdlg); + if (!pc) return; + + switch(ctrlId) + { + case IDC_BTN_SHOWINFO: + switch(eventId) + { + case BN_CLICKED: + ViewContainer_ShowMiniInfo(hdlg, !pc->bInfoVisible); + break; + case BN_EX_GETTEXT: + { + if (IsWindow(hctrl)) + { + // to ensure we're able to remove this for all views, we check this here + if (!ViewContainer_OnGetMiniInfoEnabled(hdlg)) + DestroyWindow(hctrl); + else + SetWindowTextW(hctrl, WASABI_API_LNGSTRINGW((pc->bInfoVisible) ? IDS_HIDE_INFO : IDS_SHOW_INFO)); + } + break; + } + } + break; + case ID_MINIINFO_SHOW: ViewContainer_ShowMiniInfo(hdlg, !pc->bInfoVisible); break; + case ID_EJECT_DISC: DriveManager_Eject(pc->cLetter, DM_EJECT_CHANGE); break; + case ID_COPY_SELECTION: SendDlgItemMessageW(hdlg, IDC_CHILDVIEW, WM_COMMAND, MAKEWPARAM(ctrlId, eventId), (LPARAM)hctrl); break; + } +} + +static void Window_OnFileTagUpdated(HWND hdlg, WORD wCode, INT_PTR param) +{ + HWND hChild = GetDlgItem(hdlg, IDC_CHILDVIEW); + if (hChild && IsWindow(hChild)) + { + SendMessageW(hChild, WM_TAGUPDATED, 0, + (LPARAM)((IPC_FILE_TAG_MAY_HAVE_UPDATED == wCode) ? AutoWideFn((LPCSTR)param) : (LPCWSTR)param)); + } +} + +static void Window_OnPluginNotify(HWND hdlg, WORD wCode, INT_PTR param) +{ + switch(wCode) + { + case DMW_MEDIUMARRIVED: Medium_OnArrived(hdlg, (CHAR)param); break; + case DMW_MEDIUMREMOVED: Medium_OnRemoved(hdlg, (CHAR)param); break; + case DMW_OPCOMPLETED: GetInfo_Completed(hdlg, (DM_NOTIFY_PARAM*)param); break; + case DMW_MODECHANGED: Drive_OnModeChanged(hdlg, (CHAR)LOWORD(param), (CHAR)(LOWORD(param) >> 8)); break; + case IPC_FILE_TAG_MAY_HAVE_UPDATED: + case IPC_FILE_TAG_MAY_HAVE_UPDATEDW: Window_OnFileTagUpdated(hdlg, wCode, param); break; + } +} + +static INT_PTR Window_OnSendFileInfo(HWND hdlg, LPCWSTR pszFileName, UINT fFlags) +{ + WEBINFOSHOW wis; + HWND hInfo = GetDlgItem(hdlg, IDC_MINIINFO); + if (!hInfo) return 0; + + wis.pszFileName = pszFileName;; + wis.fFlags = fFlags; + return (INT_PTR)SENDMLIPC(hInfo, ML_IPC_WEBINFO_SHOWINFO, (WPARAM)&wis); +} + +static void Window_OnQueryFileInfo(HWND hdlg) +{ + HWND hChild = GetDlgItem(hdlg, IDC_CHILDVIEW); + if(!hChild || !PostMessageW(hChild, WM_QUERYFILEINFO, 0, 0L)) Window_OnSendFileInfo(hdlg, L"", WISF_FORCE); +} + +INT_PTR CALLBACK CommandBar_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +static HWND ViewContainer_OnCreateCommandBar(HWND hdlg, CMDBARCREATESTRUCT *pcbcs) +{ + if (!pcbcs || !pcbcs->fnDialogProc) return NULL; + HWND hwndBar = WASABI_API_CREATEDIALOGPARAMW(pcbcs->resourceId, hdlg, CommandBar_DialogProc, (LPARAM)pcbcs); + if (hwndBar) + { + SetWindowLongPtrW(hwndBar, GWLP_ID, IDC_COMMAND_BAR); + ViewContainer_LayoutChildren(hdlg, TRUE); + ShowWindow(hwndBar, SW_SHOWNA); + } + return hwndBar; +} + +static BOOL ViewContainer_OnDestroyCommandBar(HWND hdlg) +{ + HWND hwndBar = GetDlgItem(hdlg, IDC_COMMAND_BAR); + if (!hwndBar) return FALSE; + + DestroyWindow(hwndBar); + ViewContainer_LayoutChildren(hdlg, TRUE); + return TRUE; +} + +static BOOL ViewContainer_OnGetMiniInfoVisible(HWND hdlg) +{ + HWND hctrl = GetDlgItem(hdlg, IDC_MINIINFO); + return (hctrl && IsWindowVisible(hctrl)); +} + +static BOOL ViewContainer_OnExtractDisc(HWND hdlg, WPARAM wParam, LPARAM lParam) +{ + HWND hChild = GetDlgItem(hdlg, IDC_CHILDVIEW); + return (hChild) ? (BOOL)SendMessageW(hChild, WM_EXTRACTDISC, wParam, lParam) : FALSE; +} + +static INT_PTR WINAPI DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return (INT_PTR)Window_OnInitDialog(hdlg, (HWND)wParam, lParam); + case WM_DESTROY: Window_OnDestroy(hdlg); break; + case WM_DISPLAYCHANGE: Window_OnDisplayChange(hdlg, (INT)wParam, LOWORD(lParam), HIWORD(lParam)); break; + case WM_WINDOWPOSCHANGED: ViewContainer_OnWindowPosChanged(hdlg, (WINDOWPOS*)lParam); return TRUE; + case WM_COMMAND: Window_OnCommand(hdlg, HIWORD(wParam), LOWORD(wParam), (HWND)lParam); break; + case WM_QUERYFILEINFO: Window_OnQueryFileInfo(hdlg); return 1; + case WM_SHOWFILEINFO: MSGRESULT(hdlg, Window_OnSendFileInfo(hdlg, (LPCWSTR)lParam, (UINT)wParam)); + case WM_EXTRACTDISC: MSGRESULT(hdlg, ViewContainer_OnExtractDisc(hdlg, wParam, lParam)); + case VCM_CREATECOMMANDBAR: MSGRESULT(hdlg, ViewContainer_OnCreateCommandBar(hdlg, (CMDBARCREATESTRUCT*)lParam)); + case VCM_DESTROYCOMMANDBAR: MSGRESULT(hdlg, ViewContainer_OnDestroyCommandBar(hdlg)); + case VCM_GETCOMMANDBAR: MSGRESULT(hdlg, GetDlgItem(hdlg, IDC_COMMAND_BAR)); + case VCM_GETMININFOENABLED: MSGRESULT(hdlg, ViewContainer_OnGetMiniInfoEnabled(hdlg)); + case VCM_GETMININFOVISIBLE: MSGRESULT(hdlg, ViewContainer_OnGetMiniInfoVisible(hdlg)); + case WM_USER + 0x200: MSGRESULT(hdlg, TRUE); + } + + if (msgNotify == uMsg) Window_OnPluginNotify(hdlg, (WORD)wParam, (INT_PTR)lParam); + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/view_data.cpp b/Src/Plugins/Library/ml_disc/view_data.cpp new file mode 100644 index 00000000..d21def96 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/view_data.cpp @@ -0,0 +1,675 @@ +#include "main.h" +#include <windowsx.h> +#include "resource.h" +#include "../winamp/wa_ipc.h" +#include "../nu/DialogSkinner.h" +#include "../nu/menushortcuts.h" +#include "./commandbar.h" +#include "./copyfiles.h" +#include "./settings.h" +#include <shlwapi.h> +#include <strsafe.h> + + +#define IDT_NOTIFYINFO 1985 +#define IDT_UPDATESTATUS 1986 +#define DELAY_NOTIFYINFO 200 +#define DELAY_UPDATESTATUS 5 + +#define IDC_FILEVIEW 10000 + +#define DATAVIEW_PROPW L"DATAVIEW" + +#define STRCOMP_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) + +typedef struct _DATAVIEW +{ + CHAR cLetter; + WCHAR szSongInfoCache[MAX_PATH]; +} DATAVIEW; + + +static INT_PTR WINAPI DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +INT_PTR WINAPI DataCmdBar_DialogProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +static void CALLBACK DataViewTimer_OnNotifyInfoElapsed(HWND hdlg, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); +static void CALLBACK DataViewTimer_OnStatusUpdateElapsed(HWND hdlg, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); + +HWND CreateCdDataViewWindow(HWND hwndParent, CHAR cLetter) +{ + return WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_CDROM_DATA, hwndParent, DlgProc, (LPARAM)cLetter); +} + +#define GetDataView(__hwnd) ((DATAVIEW*)GetPropW(__hwnd, DATAVIEW_PROPW)) + +static void DataView_NotifyInfoWindow(HWND hdlg, INT iFile, BOOL bForceRefresh) +{ + DATAVIEW *pdv = GetDataView(hdlg); + + HWND hParent = GetParent(hdlg); + if (hParent) + { + wchar_t szPath[MAX_PATH], *pszPath; + szPath[0] = L'\0'; + if (-1 != iFile) + { + HWND hfv = GetDlgItem(hdlg, IDC_FILEVIEW); + if (hfv) + { + if (FileView_GetCurrentPath(hfv, szPath, ARRAYSIZE(szPath)) && + S_OK == StringCchCatW(szPath, ARRAYSIZE(szPath), L"\\")) + { + FVITEM item; + item.mask = FVIF_TEXT | FVIF_TYPE; + INT l = lstrlenW(szPath); + pszPath = szPath + l; + item.cchTextMax = l; + item.pszText = pszPath; + item.cchTextMax = ARRAYSIZE(szPath) - item.cchTextMax; + if (!FileView_GetFile(hfv, iFile, &item) || FVFT_AUDIO != item.wType) szPath[0] = L'\0'; + else if (item.pszText != szPath) StringCchCopy(szPath, ARRAYSIZE(szPath), item.pszText); + } + else szPath[0] = L'\0'; + } + } + + if (pdv && !bForceRefresh && + CSTR_EQUAL == CompareString(STRCOMP_INVARIANT, NORM_IGNORECASE, pdv->szSongInfoCache, -1, szPath, -1)) + { + return; + } + SendMessageW(hParent, WM_SHOWFILEINFO, (WPARAM)((bForceRefresh) ? WISF_FORCE : WISF_NORMAL), (LPARAM)szPath); + if (pdv) StringCchPrintfW(pdv->szSongInfoCache, sizeof(pdv->szSongInfoCache)/sizeof(pdv->szSongInfoCache[0]), szPath); + } +} + +static void DataViewStatus_UpdateText(HWND hdlg) +{ + WCHAR szStatus[256] = {0}; + + HWND hFileView = GetDlgItem(hdlg, IDC_FILEVIEW); + + HWND hbar = ViewContainer_GetCmdBar(GetParent(hdlg)); + if (!hbar) return; + + if (hFileView) + FileView_GetStatusText(hFileView, szStatus, sizeof(szStatus)/sizeof(szStatus[0])); + DataView_NotifyInfoWindow(hdlg, -1, FALSE); + SetWindowTextW(hbar, szStatus); +} +typedef struct _COLUMN +{ + INT id; + INT width; +} COLUMN; + +static COLUMN defaultColumns[] = +{ + { FVCOLUMN_NAME, 200 }, + { FVCOLUMN_SIZE, 82 }, + { FVCOLUMN_TYPE, 64 }, + { FVCOLUMN_MODIFIED, 140 }, + { FVCOLUMN_EXTENSION, 64 }, +}; + +static LPTSTR DataView_ColumnsToStr(LPTSTR pszText, size_t cchTextMax, COLUMN *pColumns, INT count) +{ + if (!pszText || cchTextMax < 1) return NULL; + pszText[0] = TEXT('\0'); + + if (!pColumns) return pszText; + LPTSTR pc = pszText; + for(int i = 0; i < count; i++) + { + HRESULT hr = StringCchPrintfEx(pc, cchTextMax, &pc, &cchTextMax, STRSAFE_IGNORE_NULLS, + TEXT("%c(%d, %d)"), ((0 == i) ? TEXT(' ') : TEXT(',')), pColumns[i].id, pColumns[i].width); + if (S_OK != hr) return NULL; + } + return pszText; +} + +static void DataView_LoadFileViewColumns(HWND hdlg) +{ + UINT szColumns[256] = {0}; + HWND hctrl = GetDlgItem(hdlg, IDC_FILEVIEW); + if (!hctrl) return; + + INT count = FileView_GetColumnArray(hctrl, ARRAYSIZE(szColumns), szColumns); + for (int i = count-1; i >= 0; i--) FileView_DeleteColumn(hctrl, szColumns[i]); + TCHAR szColumnList[4096] = {0}; + + if (S_OK != Settings_ReadValue(C_DATAVIEW, DVF_COLUMNLIST, szColumnList, sizeof(szColumnList)) || + TEXT('\0') == *szColumnList) + { + DataView_ColumnsToStr(szColumnList, ARRAYSIZE(szColumnList), defaultColumns, ARRAYSIZE(defaultColumns)); + } + + for (LPCTSTR pc = szColumnList, pBlock = NULL; TEXT('\0') != *pc; pc++) + { + if (TEXT('(') == *pc) pBlock = (pc + 1); + else if (TEXT(')') == *pc) + { + if (pBlock && pBlock != pc) + { + FVCOLUMN fvc; + fvc.mask = 0; + while (TEXT(' ') == *pBlock && pBlock != pc) pBlock++; + if (pBlock != pc) + { + fvc.id = StrToInt(pBlock); + while (TEXT(',') != *pBlock && pBlock != pc) pBlock++; + if (pBlock != pc) + { + while ((TEXT(',') == *pBlock || TEXT(' ') == *pBlock) && pBlock != pc) pBlock++; + if (pBlock != pc) + { + fvc.width = StrToInt(pBlock); + if (fvc.width > 0) fvc.mask |= FVCF_WIDTH; + } + } + FileView_InsertColumn(hctrl, &fvc); + } + } + pBlock = NULL; + } + } + + INT orderBy, orderAsc; + Settings_GetInt(C_DATAVIEW, DVF_ORDERBY, &orderBy); + Settings_GetBool(C_DATAVIEW, DVF_ORDERASC, &orderAsc); + FileView_SetSort(hctrl, orderBy, orderAsc); +} + +static void DataView_SaveFileViewColumns(HWND hdlg) +{ + UINT szOrder[256] = {0}; + COLUMN szColumns[256] = {0}; + TCHAR szBuffer[1024] = {0}; + + HWND hctrl = GetDlgItem(hdlg, IDC_FILEVIEW); + if (!hctrl) return; + + INT count = FileView_GetColumnArray(hctrl, ARRAYSIZE(szOrder), szOrder); + for (int i = 0; i < count; i++) + { + szColumns[i].id = szOrder[i]; + szColumns[i].width = FileView_GetColumnWidth(hctrl, szOrder[i]); + } + DataView_ColumnsToStr(szBuffer, ARRAYSIZE(szBuffer), szColumns, count); + Settings_SetString(C_DATAVIEW, DVF_COLUMNLIST, szBuffer); + + DWORD sort = FileView_GetSort(hctrl); + Settings_SetInt(C_DATAVIEW, DVF_ORDERBY, LOWORD(sort)); + Settings_SetBool(C_DATAVIEW, DVF_ORDERASC, HIWORD(sort)); + + +} +static UINT DataView_ReadFileViewStyle() +{ + UINT style = 0; + INT nVal; + + style = FVS_DETAILVIEW; + if (S_OK == Settings_GetInt(C_DATAVIEW, DVF_VIEWMODE, &nVal)) + { + switch(nVal) + { + case FVS_ICONVIEW: + case FVS_LISTVIEW: + style = nVal; + break; + } + } + + if (S_OK == Settings_GetInt(C_DATAVIEW, DVF_SHOWAUDIO, &nVal) && nVal) style |= FVS_SHOWAUDIO; + if (S_OK == Settings_GetInt(C_DATAVIEW, DVF_SHOWVIDEO, &nVal) && nVal) style |= FVS_SHOWVIDEO; + if (S_OK == Settings_GetInt(C_DATAVIEW, DVF_SHOWPLAYLIST, &nVal) && nVal) style |= FVS_SHOWPLAYLIST; + if (S_OK == Settings_GetInt(C_DATAVIEW, DVF_SHOWUNKNOWN, &nVal) && nVal) style |= FVS_SHOWUNKNOWN; + if (S_OK == Settings_GetInt(C_DATAVIEW, DVF_HIDEEXTENSION, &nVal) && nVal) style |= FVS_HIDEEXTENSION; + if (S_OK == Settings_GetInt(C_DATAVIEW, DVF_IGNOREHIDDEN, &nVal) && nVal) style |= FVS_IGNOREHIDDEN; + if (S_OK == Settings_GetInt(C_GLOBAL, GF_ENQUEUEBYDEFAULT, &nVal) && nVal) + style |= FVS_ENQUEUE; + + return style; +} + +static void DataView_SaveFileViewStyle(UINT uStyle) +{ + Settings_SetInt(C_DATAVIEW, DVF_VIEWMODE, (FVS_VIEWMASK & uStyle)); + Settings_SetBool(C_DATAVIEW, DVF_SHOWAUDIO, (FVS_SHOWAUDIO & uStyle)); + Settings_SetBool(C_DATAVIEW, DVF_SHOWVIDEO, (FVS_SHOWVIDEO & uStyle)); + Settings_SetBool(C_DATAVIEW, DVF_SHOWPLAYLIST, (FVS_SHOWPLAYLIST & uStyle)); + Settings_SetBool(C_DATAVIEW, DVF_SHOWUNKNOWN, (FVS_SHOWUNKNOWN & uStyle)); + Settings_SetBool(C_DATAVIEW, DVF_HIDEEXTENSION, (FVS_HIDEEXTENSION & uStyle)); + Settings_SetBool(C_DATAVIEW, DVF_IGNOREHIDDEN, (FVS_IGNOREHIDDEN & uStyle)); +} + +static BOOL DataView_OnInitDialog(HWND hdlg, HWND hwndFocus, LPARAM lParam) +{ + RECT rc; + HWND hctrl; + + DATAVIEW *pdv = (DATAVIEW*)calloc(1, sizeof(DATAVIEW)); + if (pdv) + { + pdv->cLetter = (CHAR)lParam; + pdv->szSongInfoCache[0] = L'\0'; + SetPropW(hdlg, DATAVIEW_PROPW, pdv); + } + + GetClientRect(hdlg, &rc); + + MLSkinWindow2(plugin.hwndLibraryParent, hdlg, SKINNEDWND_TYPE_AUTO, SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS); + + MLFILEVIEWCREATESTRUCT fvcs; + fvcs.hwndParent = hdlg; + fvcs.hwndInsertAfter = hdlg; + fvcs.fStyle = DataView_ReadFileViewStyle(); + fvcs.x = 0; + fvcs.y = 0; + fvcs.cx = rc.right - rc.left; + fvcs.cy = rc.bottom - rc.top - 4; + hctrl = (HWND)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_CREATEFILEVIEW, (WPARAM)&fvcs); + + if (hctrl) + { + wchar_t szRoot[] = L"x:"; + if (pdv) szRoot[0] = pdv->cLetter; + //szRoot[0] = L'C'; + + FileView_SetRoot(hctrl, szRoot); + SetWindowLongPtrW(hctrl, GWLP_ID, IDC_FILEVIEW); + + DataView_LoadFileViewColumns(hdlg); + SetWindowLongPtrW(hctrl, GWL_STYLE, GetWindowLongPtrW(hctrl, GWL_STYLE) | WS_VISIBLE); + + INT nPos; + if (S_OK == Settings_GetInt(C_DATAVIEW, DVF_DIVIDERPOS, &nPos)) + FileView_SetDividerPos(hctrl, nPos, FVRF_NOREDRAW); + } + + ViewContainer_CreateCmdBar(GetParent(hdlg), hdlg, IDD_COMMANDBAR_DATA, DataCmdBar_DialogProc, (ULONG_PTR)hctrl); + + DataView_NotifyInfoWindow(hdlg, -1, TRUE); // ignore cache + SendMessage(hdlg, WM_COMMAND, MAKEWPARAM(ID_DRIVE_MODE_CHANGED, 0), 0L); + + TCHAR szRoot[MAX_PATH] = {0}; + if (hctrl && S_OK == Settings_ReadString(C_DATAVIEW, DVF_LASTFOLDER, szRoot, ARRAYSIZE(szRoot))) + FileView_SetCurrentPath(hctrl, szRoot, TRUE); + + return FALSE; +} + +static void DataView_OnDestroy(HWND hdlg) +{ + KillTimer(hdlg, IDT_NOTIFYINFO); + DataView_NotifyInfoWindow(hdlg, -1, FALSE); + + HWND hView = GetDlgItem(hdlg, IDC_FILEVIEW); + if (hView) + { + WCHAR szRoot[MAX_PATH] = {0}; + FileView_GetCurrentPath(hView, szRoot, ARRAYSIZE(szRoot)); + Settings_SetString(C_DATAVIEW, DVF_LASTFOLDER, szRoot); + + DataView_SaveFileViewColumns(hdlg); + DataView_SaveFileViewStyle(FileView_GetStyle(hView)); + + Settings_SetInt(C_DATAVIEW, DVF_DIVIDERPOS, FileView_GetDividerPos(hView)); + + } + DATAVIEW *pdv = GetDataView(hdlg); + if (pdv) + { + RemovePropW(hdlg, DATAVIEW_PROPW); + free(pdv); + } + ViewContainer_DestroyCmdBar(GetParent(hdlg)); +} + +static void CALLBACK DataViewTimer_OnStatusUpdateElapsed(HWND hdlg, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + KillTimer(hdlg, idEvent); + DataViewStatus_UpdateText(hdlg); + + BOOL enablePlay = FALSE; + HWND hctrl = GetDlgItem(hdlg, IDC_FILEVIEW); + + if (hctrl && FileView_GetSelectedCount(hctrl) > 0) + { + enablePlay = (-1 != FileView_GetNextFile(hctrl, -1, FVNF_PLAYABLE | FVNF_SELECTED)); + } + + HWND hbar = ViewContainer_GetCmdBar(GetParent(hdlg)); + if (hbar) + { + if (NULL != (hctrl = GetDlgItem(hbar, IDC_BTN_PLAYEX))) EnableWindow(hctrl, enablePlay); + if (NULL != (hctrl = GetDlgItem(hbar, IDC_BTN_COPY))) EnableWindow(hctrl, enablePlay); + } + +} + +static void CALLBACK DataViewTimer_OnNotifyInfoElapsed(HWND hdlg, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + KillTimer(hdlg, IDT_NOTIFYINFO); + HWND hFileView = GetDlgItem(hdlg, IDC_FILEVIEW); + + INT iFile = -1; + if (hFileView) + { + iFile = FileView_GetSelectedCount(hFileView); + if (1 != iFile) iFile = -1; + else iFile = FileView_GetNextFile(hFileView, -1, FVNF_FOCUSED); + } + + DataView_NotifyInfoWindow(hdlg, iFile, FALSE); +} + +static void DataView_OnWindowPosChanged(HWND hdlg, WINDOWPOS *pwp) +{ + if (0 == (SWP_NOSIZE & pwp->flags)) + { + HWND hctrl; + RECT rc, rw; + GetClientRect(hdlg, &rc); + + hctrl = GetDlgItem(hdlg, IDC_FILEVIEW); + if (hctrl && GetWindowRect(hctrl, &rw)) + { + MapWindowPoints(HWND_DESKTOP, hdlg, (POINT*)&rw, 2); + SetWindowPos(hctrl, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | ((SWP_NOREDRAW | SWP_NOCOPYBITS) & pwp->flags)); + } + } +} + + + +static void DataView_OnCopySelection(HWND hdlg) +{ + LPWSTR *ppszFiles = NULL; + ULONGLONG *pFSizes; + INT count, iFile; + size_t cchPath, cchFile; + WCHAR szPath[MAX_PATH] = {0}; + FVITEM file = {0}; + + HWND hctrl = GetDlgItem(hdlg, IDC_FILEVIEW); + if (!hctrl) return; + + + count = FileView_GetSelectedCount(hctrl); + if (count < 1) return; + + if (!FileView_GetCurrentPath(hctrl, szPath, sizeof(szPath)/sizeof(szPath[0])) || + S_OK != StringCchLengthW(szPath, sizeof(szPath)/sizeof(szPath[0]), &cchPath)) return; + + ppszFiles = (LPWSTR*)CoTaskMemAlloc(sizeof(LPWSTR)*count); + pFSizes = (ULONGLONG*)CoTaskMemAlloc(sizeof(ULONGLONG)*count); + if (!ppszFiles || !pFSizes) + { + if (ppszFiles) CoTaskMemFree(ppszFiles); + if (pFSizes) CoTaskMemFree(pFSizes); + return; + } + + iFile = -1; + count = 0; + file.mask = FVIF_TEXT | FVIF_SIZE; + TCHAR szBuffer[MAX_PATH] = {0}; + while (-1 != (iFile = FileView_GetNextFile(hctrl, iFile, FVNF_SELECTED | FVNF_PLAYABLE))) + { + file.pszText = szBuffer; + file.cchTextMax = ARRAYSIZE(szBuffer); + if (FileView_GetFile(hctrl, iFile, &file)) + { + cchFile = (file.pszText) ? lstrlenW(file.pszText) : 0; + if (cchFile) + { + pFSizes[count] = (ULONGLONG)(((__int64)file.dwSizeHigh << 32) | file.dwSizeLow); + ppszFiles[count] = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR)*(cchPath + cchFile + 4)); + if (ppszFiles[count]) + { + PathCombineW(ppszFiles[count], szPath, file.pszText); + count++; + } + } + } + } + + if (!MLDisc_CopyFiles(hdlg, ppszFiles, pFSizes, count)) + { + if (ppszFiles) + { + for (int i = 0; i < count; i++) CoTaskMemFree(ppszFiles[i]); + CoTaskMemFree(ppszFiles); + } + if (pFSizes) CoTaskMemFree(pFSizes); + } +} + +static void DataView_OnDriveModeChanged(HWND hdlg) +{ + DATAVIEW *pdv = GetDataView(hdlg); + if (!pdv) return; + + HWND hbar; + if (NULL != (hbar = ViewContainer_GetCmdBar(GetParent(hdlg)))) + { + HWND hctrl; + if (NULL != (hctrl = GetDlgItem(hbar, IDC_BTN_EJECT))) + { + UINT cMode = DriveManager_GetDriveMode(pdv->cLetter); + EnableWindow(hctrl, (DM_MODE_READY == cMode)); + } + } + +} + +static void DataView_OnCommand(HWND hdlg, INT eventId, INT ctrlId, HWND hwndCtrl) +{ + switch(ctrlId) + { + case ID_COPY_SELECTION: + DataView_OnCopySelection(hdlg); + break; + case ID_DRIVE_MODE_CHANGED: + DataView_OnDriveModeChanged(hdlg); + break; + } +} + +static void FileView_OnFolderChanged(HWND hdlg, NMHDR *phdr) +{ + DataView_NotifyInfoWindow(hdlg, -1, FALSE); + SetTimer(hdlg, IDT_UPDATESTATUS, DELAY_UPDATESTATUS, DataViewTimer_OnStatusUpdateElapsed); +} + +static void FileView_OnStatusChanged(HWND hdlg, NMHDR *phdr) +{ + SetTimer(hdlg, IDT_UPDATESTATUS, DELAY_UPDATESTATUS, DataViewTimer_OnStatusUpdateElapsed); +} + +static void FileView_OnFileStateChanged(HWND hdlg, NMFVSTATECHANGED *pnmsc) +{ + SetTimer(hdlg, IDT_UPDATESTATUS, DELAY_UPDATESTATUS, DataViewTimer_OnStatusUpdateElapsed); + SetTimer(hdlg, IDT_NOTIFYINFO, DELAY_NOTIFYINFO, DataViewTimer_OnNotifyInfoElapsed); +} + +static void FileView_OnDoubleClick(HWND hdlg, NMFVFILEACTIVATE *pnma) +{ + if (-1 == pnma->iFile) return; + + HWND hctrl = GetDlgItem(hdlg, IDC_FILEVIEW); + if (!hctrl) return; + + SendMessageW(hctrl, WM_COMMAND, + MAKEWPARAM(FileView_GetActionCommand(hctrl, (FVS_ENQUEUE & (FileView_GetStyle(hctrl)) ? FVA_ENQUEUE : FVA_PLAY)), 0), 0L); +} + +static void FileView_OnUninitOptionsMenu(HWND hdlg, HMENU hMenu, UINT uCommand) +{ + HWND hParent = GetParent(hdlg); + if (!hMenu || !hParent || !ViewContainer_GetMiniInfoEnabled(hParent)) return; + INT index = GetMenuItemCount(hMenu); + + MENUITEMINFOW mii = { sizeof(MENUITEMINFOW), }; + mii.fMask = MIIM_ID; + while (index--) + { + if (GetMenuItemInfoW(hMenu, index, TRUE, &mii) && ID_MINIINFO_SHOW == mii.wID) + { + if (DeleteMenu(hMenu, index, MF_BYPOSITION)) + DeleteMenu(hMenu, --index, MF_BYPOSITION); + break; + } + } +} + +static void FileView_OnInitOptionsMenu(HWND hdlg, HMENU hMenu) +{ + INT index; + HWND hParent; + + hParent = GetParent(hdlg); + if (!hMenu || !hParent || !ViewContainer_GetMiniInfoEnabled(hParent)) return; + + MENUITEMINFOW mii = { sizeof(MENUITEMINFOW), }; + + index = GetMenuItemCount(hMenu); + + mii.fMask = MIIM_TYPE; + mii.fType = MFT_SEPARATOR; + + if (InsertMenuItemW(hMenu, index, TRUE, &mii)) + { + wchar_t szText[1024] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_SHOW_INFO, szText, sizeof(szText)/sizeof(szText[0])); + + if (WASABI_API_APP) + { + HACCEL szAccel[24] = {0}; + INT c = WASABI_API_APP->app_getAccelerators(GetParent(hdlg), szAccel, sizeof(szAccel)/sizeof(szAccel[0]), FALSE); + AppendShortcutText(szText, sizeof(szText)/sizeof(szText[0]), ID_MINIINFO_SHOW, szAccel, c, MSF_REPLACE); + } + + index++; + mii.fMask = MIIM_STRING | MIIM_STATE | MIIM_ID; + mii.dwTypeData = szText; + mii.wID = ID_MINIINFO_SHOW; + mii.fState = (ViewContainer_GetMiniInfoVisible(hParent)) ? MFS_CHECKED : MFS_UNCHECKED; + + InsertMenuItemW(hMenu, index, TRUE, &mii); + } +} + +static void FileView_OnInitFileContextMenu(HWND hdlg, HMENU hMenu, HWND hView) +{ + HWND hbar = ViewContainer_GetCmdBar(GetParent(hdlg)); + HWND hButton = (hbar) ? GetDlgItem(hbar, IDC_BTN_COPY) : NULL; + if (!hButton) return; + + wchar_t szText[1024] = {0}; + GetWindowTextW(hButton, szText, sizeof(szText)/sizeof(szText[0])); + + if (WASABI_API_APP) + { + HACCEL szAccel[24] = {0}; + INT c = WASABI_API_APP->app_getAccelerators(GetParent(hdlg), szAccel, sizeof(szAccel)/sizeof(szAccel[0]), FALSE); + AppendShortcutText(szText, sizeof(szText)/sizeof(szText[0]), ID_COPY_SELECTION, szAccel, c, MSF_REPLACE); + } + + MENUITEMINFOW mii = { sizeof(MENUITEMINFOW), }; + mii.fMask = MIIM_STRING | MIIM_STATE | MIIM_ID; + mii.dwTypeData = szText; + mii.wID = ID_COPY_SELECTION; // TODO: make id uniqueue + mii.fState = (IsWindowEnabled(hButton)) ? MFS_ENABLED : MFS_DISABLED; + + InsertMenuItemW(hMenu, 2, TRUE, &mii); +} + +static BOOL FileView_OnInitMenu(HWND hdlg, NMFVMENU *pnm) +{ + switch(pnm->uMenuType) + { + case FVMENU_OPTIONS: FileView_OnInitOptionsMenu(hdlg, pnm->hMenu); break; + case FVMENU_FILEOPCONTEXT: FileView_OnInitFileContextMenu(hdlg, pnm->hMenu, pnm->hdr.hwndFrom); break; + } + return FALSE; +} + +static void FileView_OnUninitMenu(HWND hdlg, NMFVMENU *pnm) +{ + switch(pnm->uMenuType) + { + case FVMENU_OPTIONS: FileView_OnUninitOptionsMenu(hdlg, pnm->hMenu, pnm->uCommand); break; + case FVMENU_FILEOPCONTEXT: DeleteMenu(pnm->hMenu, ID_COPY_SELECTION, MF_BYCOMMAND); break; + } +} + +static BOOL FileView_OnMenuCommand(HWND hdlg, NMFVMENU *pnm) +{ + switch(pnm->uCommand) + { + case ID_MINIINFO_SHOW: + SendMessageW(GetParent(hdlg), WM_COMMAND, MAKEWPARAM(ID_MINIINFO_SHOW, 0), 0L); + return TRUE; + case ID_COPY_SELECTION: + SendMessageW(hdlg, WM_COMMAND, MAKEWPARAM(ID_COPY_SELECTION, 0), 0L); + return TRUE; + } + return FALSE; +} + +static INT_PTR DataView_OnNotify(HWND hdlg, INT ctrlId, NMHDR *phdr) +{ + switch(phdr->idFrom) + { + case IDC_FILEVIEW: + switch(phdr->code) + { + case FVN_FOLDERCHANGED: FileView_OnFolderChanged(hdlg, phdr); break; + case FVN_STATECHANGED: FileView_OnFileStateChanged(hdlg, (NMFVSTATECHANGED*)phdr); break; + case FVN_STATUSCHANGED: FileView_OnStatusChanged(hdlg, phdr); break; + case NM_DBLCLK: FileView_OnDoubleClick(hdlg, (NMFVFILEACTIVATE*)phdr); break; + case FVN_INITMENU: return FileView_OnInitMenu(hdlg, (NMFVMENU*)phdr); + case FVN_UNINITMENU: FileView_OnUninitMenu(hdlg, (NMFVMENU*)phdr); break; + case FVN_MENUCOMMAND: return FileView_OnMenuCommand(hdlg, (NMFVMENU*)phdr); + } + break; + } + return 0; +} + + +static void DataView_OnQueryInfo(HWND hdlg) +{ + KillTimer(hdlg, IDT_NOTIFYINFO); + DataView_NotifyInfoWindow(hdlg, -1, TRUE); + SetTimer(hdlg, IDT_NOTIFYINFO, DELAY_NOTIFYINFO, DataViewTimer_OnNotifyInfoElapsed); +} + +static void DataView_OnDisplayChange(HWND hdlg) +{ + HWND hctrl = GetDlgItem(hdlg, IDC_FILEVIEW); + if (!hctrl) return; + BOOL bVal; + Settings_GetBool(C_GLOBAL, GF_ENQUEUEBYDEFAULT, &bVal); + FileView_SetStyle(hctrl, (bVal) ? FVS_ENQUEUE : 0L, FVS_ENQUEUE); +} + +static INT_PTR WINAPI DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: return DataView_OnInitDialog(hdlg, (HWND)wParam, lParam); + case WM_DESTROY: DataView_OnDestroy(hdlg); break; + case WM_WINDOWPOSCHANGED: DataView_OnWindowPosChanged(hdlg, (WINDOWPOS*)lParam); return TRUE; + case WM_COMMAND: DataView_OnCommand(hdlg, HIWORD(wParam), LOWORD(wParam), (HWND)lParam); break; + case WM_NOTIFY: MSGRESULT(hdlg, DataView_OnNotify(hdlg, (INT)wParam, (LPNMHDR) lParam)); + case WM_QUERYFILEINFO: DataView_OnQueryInfo(hdlg); break; + case WM_DISPLAYCHANGE: DataView_OnDisplayChange(hdlg); break; + + } + + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/view_info.cpp b/Src/Plugins/Library/ml_disc/view_info.cpp new file mode 100644 index 00000000..609405f9 --- /dev/null +++ b/Src/Plugins/Library/ml_disc/view_info.cpp @@ -0,0 +1,127 @@ +#include "main.h" +#include "./resource.h" +#include "../nu/DialogSkinner.h" + +#include <windowsx.h> + +static HBRUSH hbBack = NULL; + +static INT_PTR WINAPI DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +// public function +HWND CreateInfoWindow(HWND hwndParent, CHAR cLetter) +{ + return WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_INFO, hwndParent, DlgProc, (LPARAM)cLetter); +} + +static INT_PTR Window_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) +{ + SendMessageW(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_BTN_SHOWINFO, BN_EX_GETTEXT), (LPARAM)GetDlgItem(hwnd, IDC_BTN_SHOWINFO)); + return 0; +} + +static void Window_OnDestroy(HWND hwnd) +{ + if (hbBack) + { + DeleteObject(hbBack); + hbBack = NULL; + } +} + +static void Window_OnDisplayChange(HWND hwnd, INT dpi, INT resX, INT resY) +{ + if (hbBack) + { + DeleteObject(hbBack); + hbBack = NULL; + } + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN); +} + +static void Window_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp) +{ + HWND hwndCtrl; + RECT rw; + + hwndCtrl = GetDlgItem(hwnd, IDC_BTN_SHOWINFO); + if(hwndCtrl) + { + GetWindowRect(hwndCtrl, &rw); + OffsetRect(&rw, -rw.left, -rw.top); + SetWindowPos(hwndCtrl, NULL, pwp->cx - rw.right, pwp->cy - rw.bottom, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS); + } + + hwndCtrl = GetDlgItem(hwnd, IDC_LBL_TEXT); + if(hwndCtrl) + { + GetWindowRect(hwndCtrl, &rw); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2); + SetWindowPos(hwndCtrl, NULL, 0, 0, pwp->cx - rw.left - 2, pwp->cy - 22 - rw.top, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS); + } + if (0 == (SWP_NOREDRAW & pwp->flags)) + { + InvalidateRect(hwnd, NULL, TRUE); + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); + } +} + +static void Window_OnCommand(HWND hwnd, INT eventId, INT ctrlId, HWND hwndCtrl) +{ + switch(ctrlId) + { + case IDC_BTN_SHOWINFO: + switch(eventId) + { + case BN_CLICKED: + SendMessageW(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(ctrlId, eventId),(LPARAM)hwndCtrl); + break; + } + break; + } +} + +static HBRUSH Window_OnStaticColor(HWND hwnd, HDC hdc) +{ + if (!hbBack) hbBack = CreateSolidBrush(dialogSkinner.Color(WADLG_ITEMBG)); + SetTextColor(hdc, dialogSkinner.Color(WADLG_ITEMFG)); + SetBkColor(hdc, dialogSkinner.Color(WADLG_ITEMBG)); + return hbBack; +} + +static void Window_OnPaint(HWND hwnd) +{ + int tab[] = { IDC_LBL_TEXT | DCW_SUNKENBORDER}; + dialogSkinner.Draw(hwnd, tab, 1); +} + +static void Window_OnQueryInfo(HWND hwnd) +{ + HWND hwndParent; + hwndParent = GetParent(hwnd); + if (hwndParent) SendMessageW(hwndParent, WM_SHOWFILEINFO, (WPARAM)WISF_NORMAL, (LPARAM)L""); +} + +static INT_PTR WINAPI DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + INT_PTR result; + + if (WM_CTLCOLORSTATIC == uMsg) return (INT_PTR)Window_OnStaticColor(hwnd, (HDC)wParam); + + result = dialogSkinner.Handle(hwnd, uMsg, wParam, lParam); + if (result) return result; + + switch(uMsg) + { + case WM_INITDIALOG: return (INT_PTR)Window_OnInitDialog(hwnd, (HWND)wParam, lParam); + case WM_DESTROY: Window_OnDestroy(hwnd); break; + case WM_DISPLAYCHANGE: Window_OnDisplayChange(hwnd, (INT)wParam, LOWORD(lParam), HIWORD(lParam)); break; + case WM_WINDOWPOSCHANGED: Window_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); break; + case WM_COMMAND: Window_OnCommand(hwnd, HIWORD(wParam), LOWORD(wParam), (HWND)lParam); break; + case WM_PAINT: Window_OnPaint(hwnd); break; + case WM_QUERYFILEINFO: Window_OnQueryInfo(hwnd); break; + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/view_ripburn.cpp b/Src/Plugins/Library/ml_disc/view_ripburn.cpp new file mode 100644 index 00000000..b8e55e9c --- /dev/null +++ b/Src/Plugins/Library/ml_disc/view_ripburn.cpp @@ -0,0 +1,567 @@ +#include "main.h" +#include "resource.h" +#include "../nu/DialogSkinner.h" +#include "../nu/ChildSizer.h" +#include "config.h" +#include ".\driveListBox.h" +#include ".\infoBox.h" +#include ".\primosdk_helper.h" +#include <strsafe.h> + +static ChildWndResizeItem ripburn_rlist[]= +{ + {IDC_LBL_DRIVES, 0x0000}, + {IDC_LIST_DRIVES, 0x0001}, + {IDC_LBL_INFO_DRIVE, 0x0010}, + {IDC_LBL_INFO_MEDIUM, 0x0011}, + {IDC_LBL_DRIVE_LETTER_VAL, 0x0010}, + {IDC_LBL_DRIVE_DESCRIPTION_VAL,0x0010}, + {IDC_LBL_DRIVE_BUS_VAL, 0x0010}, + {IDC_LBL_DRIVE_TYPES_VAL, 0x0010}, + {IDC_LBL_MEDIUM_UPDATE, 0x0010}, + {IDC_LBL_MEDIUM_CAPACITY_VAL, 0x0010}, + {IDC_LBL_MEDIUM_TRACKN_VAL, 0x0010}, + {IDC_LBL_MEDIUM_ERASEABLE_VAL, 0x0010}, + {IDC_LBL_MEDIUM_RECORDABLE_VAL,0x0010}, + {IDC_LBL_MEDIUM_FORMAT_VAL, 0x0010}, + {IDC_LBL_MEDIUM_ADDINFO_VAL, 0x0010}, + {IDC_LBL_MEDIUM_DISC_VAL, 0x0010}, + {IDC_BTN_REFRESH, 0x0101}, +}; + +static DriveListBox *driveListBox = NULL; +static MLInfoBox *driveInfo = NULL; +static MLInfoBox *mediumInfo = NULL; + +static HBRUSH lblHeaderBrush = NULL; +static HBRUSH lblValueBrush = NULL; + +static UINT msgNotify = 0; +static CHAR activeDrive = 0x00; + +static void CALLBACK FreeAsyncParam(DM_NOTIFY_PARAM *phdr) +{ + DM_UNITINFO_PARAM *pui = NULL; + DM_UNITINFO2_PARAM *pui2 = NULL; + if(!phdr) return; + + switch(phdr->opCode) + { + case DMOP_UNITINFO: + pui = (DM_UNITINFO_PARAM*)phdr; + if (pui->pszDesc) free(pui->pszDesc); + break; + case DMOP_UNITINFO2: + pui2 = (DM_UNITINFO2_PARAM*)phdr; + if (pui2->pdwTypes) free(pui2->pdwTypes); + break; + } + free(phdr); +} + +static void UpdateDriveInfo(HWND hwndDlg, CHAR cLetter) +{ + DM_NOTIFY_PARAM header = {0}; + DM_UNITINFO_PARAM *pui = NULL; + DM_UNITINFO2_PARAM *pui2 = NULL; + DM_DISCINFOEX_PARAM *pdi = NULL; + DM_DISCINFO2_PARAM *pdi2 = NULL; + wchar_t message[128] = {0}; + + activeDrive = cLetter; + + if(!PrimoSDKHelper_IsLoaded()) + { + WASABI_API_LNGSTRINGW_BUF(IDS_NO_INFO_AVAILABLE,message,128); + } + + SetDlgItemTextA(hwndDlg, IDC_LBL_DRIVE_LETTER_VAL, &cLetter); + SetDlgItemText(hwndDlg, IDC_LBL_DRIVE_DESCRIPTION_VAL, message); + SetDlgItemText(hwndDlg, IDC_LBL_DRIVE_BUS_VAL, message); + SetDlgItemText(hwndDlg, IDC_LBL_DRIVE_TYPES_VAL, message); + SetDlgItemTextA(hwndDlg, IDC_LBL_MEDIUM_DISC_VAL, NULL); + SetDlgItemTextA(hwndDlg, IDC_LBL_MEDIUM_CAPACITY_VAL, NULL); + SetDlgItemTextA(hwndDlg, IDC_LBL_MEDIUM_FORMAT_VAL, NULL); + SetDlgItemTextA(hwndDlg, IDC_LBL_MEDIUM_ERASEABLE_VAL, NULL); + SetDlgItemTextA(hwndDlg, IDC_LBL_MEDIUM_RECORDABLE_VAL, NULL); + SetDlgItemTextA(hwndDlg, IDC_LBL_MEDIUM_TRACKN_VAL, NULL); + SetDlgItemTextA(hwndDlg, IDC_LBL_MEDIUM_ADDINFO_VAL, NULL); + + if (0 == activeDrive) return; + + ZeroMemory(&header, sizeof(DM_NOTIFY_PARAM)); + + header.callback = (INT_PTR)hwndDlg; + header.uMsg = msgNotify; + header.cLetter = cLetter; + header.fnFree = FreeAsyncParam; + + // request unitinfo + pui = (DM_UNITINFO_PARAM*)calloc(1, sizeof(DM_UNITINFO_PARAM)); + if (pui) + { + CopyMemory(&pui->header, &header, sizeof(DM_NOTIFY_PARAM)); + pui->header.fFlags = DMF_DESCRIPTION; + pui->cchDesc = 128; + pui->pszDesc = (CHAR*)calloc(pui->cchDesc, sizeof(CHAR)); + DriveManager_GetUnitInfo(pui); + } + + // request unitinfo2 + pui2 = (DM_UNITINFO2_PARAM*)calloc(1, sizeof(DM_UNITINFO2_PARAM)); + if (pui2) + { + CopyMemory(&pui2->header, &header, sizeof(DM_NOTIFY_PARAM)); + pui2->header.fFlags = DMF_TYPES; + pui2->nTypes = 32; + pui2->pdwTypes = (DWORD*)calloc(pui2->nTypes, sizeof(DWORD)); + DriveManager_GetUnitInfo2(pui2); + } + + // request discinfoex + pdi = (DM_DISCINFOEX_PARAM*)calloc(1, sizeof(DM_DISCINFOEX_PARAM)); + if (pdi) + { + CopyMemory(&pdi->header, &header, sizeof(DM_NOTIFY_PARAM)); + pdi->header.fFlags = DMF_DRIVEMODE_DAO | DMF_MEDIUMTYPE | DMF_MEDIUMFORMAT | DMF_TRACKS | DMF_USED | DMF_FREE; + DriveManager_GetDiscInfoEx(pdi); + } + + // request discinfo2 + pdi2 = (DM_DISCINFO2_PARAM*)calloc(1, sizeof(DM_DISCINFO2_PARAM)); + if (pdi2) + { + CopyMemory(&pdi2->header, &header, sizeof(DM_NOTIFY_PARAM)); + pdi2->header.fFlags = DMF_MEDIUM | DMF_MEDIUMEX; + DriveManager_GetDiscInfo2(pdi2); + } +} + +static BOOL CALLBACK EnumerateNavItemsCB(HNAVITEM hItem, DRIVE *pDrive, LPARAM param) +{ + if (!param) return FALSE; + if (pDrive) PostMessageW((HWND)param, msgNotify, (WPARAM)DMW_DRIVEADDED, (LPARAM)pDrive->cLetter); + return TRUE; +} + +static void SwitchControlVisible(HWND hwndDlg, INT ctrlId, RECT *prcParent, BOOL hide, BOOL bInvalidate = FALSE) +{ + HWND hwndCtrl = GetDlgItem(hwndDlg, ctrlId); + + if (hwndCtrl) + { + if (hide) ShowWindow(hwndCtrl, SW_HIDE); + else + { + RECT rc; + GetWindowRect(hwndCtrl, &rc); + + BOOL bVisible = ((prcParent->right > rc.right) && (prcParent->bottom > rc.bottom)); + if (bVisible != IsWindowVisible(hwndCtrl)) ShowWindow(hwndCtrl, (bVisible) ? SW_SHOWNORMAL : SW_HIDE); + if (bVisible && bInvalidate) InvalidateRect(hwndCtrl, NULL, TRUE); + } + } +} + +static void ripburn_OnDisplayChanges(HWND hwndDlg) +{ + driveListBox->SetColors(dialogSkinner.Color(WADLG_ITEMBG), + dialogSkinner.Color(WADLG_ITEMBG), + dialogSkinner.Color(WADLG_ITEMFG), + dialogSkinner.Color(WADLG_ITEMFG), + dialogSkinner.Color(WADLG_WNDFG)); + driveInfo->SetColors( dialogSkinner.Color(WADLG_ITEMBG), + dialogSkinner.Color(WADLG_LISTHEADER_FONTCOLOR), + dialogSkinner.Color(WADLG_LISTHEADER_BGCOLOR)); + mediumInfo->SetColors( dialogSkinner.Color(WADLG_ITEMBG), + dialogSkinner.Color(WADLG_LISTHEADER_FONTCOLOR), + dialogSkinner.Color(WADLG_LISTHEADER_BGCOLOR)); + + if (lblHeaderBrush) DeleteObject(lblHeaderBrush); + lblHeaderBrush = NULL; + + if (lblValueBrush) DeleteObject(lblValueBrush); + lblValueBrush = NULL; + + // fixes the view not updating correctly on colour theme changes, etc + // NOTE: ideal would be using a LayoutWindows(..) method which would + // help to resolve this as things can be offloaded to gen_ml... + RECT rc; + GetClientRect(hwndDlg, &rc); + RedrawWindow(hwndDlg, &rc, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW | RDW_UPDATENOW); +} + +static void ripburn_OnInitDialog(HWND hwndDlg) +{ + HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST_DRIVES); + + driveListBox = new DriveListBox(IDC_LIST_DRIVES); + driveListBox->SetImages(plugin.hDllInstance, IDB_LISTBOX_BACK, IDB_LISTITEM_CDDRIVE); + driveListBox->Init(hwndList); + + driveInfo = new MLInfoBox(); + driveInfo->Init(GetDlgItem(hwndDlg, IDC_LBL_INFO_DRIVE)); + + mediumInfo = new MLInfoBox(); + mediumInfo->Init(GetDlgItem(hwndDlg, IDC_LBL_INFO_MEDIUM)); + + UpdateDriveInfo(hwndDlg, 0); + + childSizer.Init(hwndDlg,ripburn_rlist,sizeof(ripburn_rlist)/sizeof(ripburn_rlist[0])); + ripburn_OnDisplayChanges(hwndDlg); + + if (!msgNotify) msgNotify = RegisterWindowMessageW(L"ripburn_notify_msg"); + + Plugin_EnumerateNavItems(EnumerateNavItemsCB, (LPARAM)hwndDlg); + Plugin_RegisterListener(hwndDlg, msgNotify, 0); +} + +static void ripburn_OnDestroy(HWND hwndDlg) +{ + Plugin_UnregisterListener(hwndDlg); + + HWND hwndLB = GetDlgItem(hwndDlg, IDC_LIST_DRIVES); + if (hwndLB) + { + INT index = (int)(INT_PTR)SendMessageW(hwndLB, LB_GETCURSEL, 0,0); + DWORD data = (LB_ERR != index) ? (DWORD)SendMessageW(hwndLB, LB_GETITEMDATA, index, 0) : 0; + if (data) g_config->WriteInt(L"last_drive", (CHAR)(0xFF & data)); + } + + if (lblHeaderBrush) DeleteObject(lblHeaderBrush); + lblHeaderBrush = NULL; + if (lblValueBrush) DeleteObject(lblValueBrush); + lblValueBrush = NULL; + + if (driveListBox) delete(driveListBox); + driveListBox = NULL; + if (driveInfo) delete(driveInfo); + driveInfo = NULL; + if (mediumInfo) delete(mediumInfo); + mediumInfo = NULL; +} + +static void ripburn_OnSize(HWND hwndDlg, int cx, int cy) +{ + RECT box; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_LBL_INFO_DRIVE), &box); + BOOL hide = FALSE; + + SwitchControlVisible(hwndDlg, IDC_LBL_DRIVE_LETTER, &box, FALSE); + SwitchControlVisible(hwndDlg, IDC_LBL_DRIVE_DESCRIPTION, &box, FALSE); + SwitchControlVisible(hwndDlg, IDC_LBL_DRIVE_BUS, &box, FALSE); + SwitchControlVisible(hwndDlg, IDC_LBL_DRIVE_TYPES,&box, FALSE); + SwitchControlVisible(hwndDlg, IDC_LBL_DRIVE_LETTER_VAL, &box, hide, TRUE); + SwitchControlVisible(hwndDlg, IDC_LBL_DRIVE_DESCRIPTION_VAL, &box, hide, TRUE); + SwitchControlVisible(hwndDlg, IDC_LBL_DRIVE_BUS_VAL, &box, hide, TRUE); + SwitchControlVisible(hwndDlg, IDC_LBL_DRIVE_TYPES_VAL, &box, hide, TRUE); + + GetWindowRect(GetDlgItem(hwndDlg, IDC_LBL_INFO_MEDIUM), &box); + hide = IsWindowVisible(GetDlgItem(hwndDlg, IDC_LBL_MEDIUM_UPDATE)); + if (hide) InvalidateRect(GetDlgItem(hwndDlg, IDC_LBL_MEDIUM_UPDATE), NULL, TRUE); + + if(PrimoSDKHelper_IsLoaded()) + /*{ + ShowWindow(GetDlgItem(hwndDlg, IDC_LBL_MEDIUM_UPDATE), SW_SHOW); + } + else*/ + { + ShowWindow(GetDlgItem(hwndDlg, IDC_LBL_MEDIUM_UPDATE), SW_HIDE); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_CAPACITY_VAL, &box, hide, TRUE); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_FORMAT_VAL, &box, hide, TRUE); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_ERASEABLE_VAL, &box, hide, TRUE); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_RECORDABLE_VAL,&box, hide, TRUE); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_TRACKN_VAL, &box, hide, TRUE); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_DISC_VAL, &box, hide, TRUE); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_ADDINFO_VAL, &box, hide, TRUE); + + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_TYPE, &box, hide); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_CAPACITY, &box, hide); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_FORMAT, &box, hide); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_ERASEABLE, &box, hide); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_RECORDABLE, &box, hide); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_TRACKN, &box, hide); + SwitchControlVisible(hwndDlg, IDC_LBL_MEDIUM_ADDINFO, &box, hide); + } +} + +static int LabelColoring(HDC hdc, HWND hwndCtrl) +{ + switch(GetDlgCtrlID(hwndCtrl)) + { + case IDC_LBL_DRIVES: + if(!lblHeaderBrush) lblHeaderBrush = CreateSolidBrush(dialogSkinner.Color(WADLG_LISTHEADER_BGCOLOR)); + SetBkMode(hdc, TRANSPARENT); + SetTextColor(hdc, dialogSkinner.Color(WADLG_LISTHEADER_FONTCOLOR)); + return (BOOL)(INT_PTR)lblHeaderBrush; + case IDC_LBL_MEDIUM_NOINFO: + case IDC_LBL_MEDIUM_CAPACITY_VAL: + case IDC_LBL_MEDIUM_TRACKN_VAL: + case IDC_LBL_MEDIUM_ERASEABLE_VAL: + case IDC_LBL_MEDIUM_RECORDABLE_VAL: + case IDC_LBL_MEDIUM_FORMAT_VAL: + case IDC_LBL_MEDIUM_DISC_VAL: + case IDC_LBL_MEDIUM_ADDINFO_VAL: + case IDC_LBL_DRIVE_LETTER_VAL: + case IDC_LBL_DRIVE_DESCRIPTION_VAL: + case IDC_LBL_DRIVE_BUS_VAL: + case IDC_LBL_DRIVE_TYPES_VAL: + case IDC_LBL_MEDIUM_UPDATE: + if(!lblValueBrush) lblValueBrush = CreateSolidBrush(dialogSkinner.Color(WADLG_ITEMBG)); + SetBkColor(hdc, dialogSkinner.Color(WADLG_ITEMBG)); + SetTextColor(hdc, dialogSkinner.Color(WADLG_ITEMFG)); + return (BOOL)(INT_PTR)lblValueBrush; + case IDC_LBL_MEDIUM_CAPACITY: + case IDC_LBL_MEDIUM_TRACKN: + case IDC_LBL_MEDIUM_ERASEABLE: + case IDC_LBL_MEDIUM_RECORDABLE: + case IDC_LBL_MEDIUM_FORMAT: + case IDC_LBL_MEDIUM_ADDINFO: + case IDC_LBL_DRIVE_LETTER: + case IDC_LBL_DRIVE_DESCRIPTION: + case IDC_LBL_DRIVE_BUS: + case IDC_LBL_DRIVE_TYPES: + case IDC_LBL_MEDIUM_TYPE: + if(!lblValueBrush) lblValueBrush = CreateSolidBrush(dialogSkinner.Color(WADLG_ITEMBG)); + SetBkMode(hdc, TRANSPARENT); + // SetBkColor(hdc, dialogSkinner.Color(WADLG_ITEMBG)); + SetTextColor(hdc, dialogSkinner.Color(WADLG_ITEMFG)); + return (BOOL)(INT_PTR)lblValueBrush; + } + return FALSE; +} + +static void Drive_OnAdded(HWND hwndDlg, CHAR cLetter) +{ + HWND hwndLB = GetDlgItem(hwndDlg, IDC_LIST_DRIVES); + if (IsWindow(hwndLB)) + { + wchar_t str[] = {cLetter, 0x00}; + INT index = (INT)SendMessageW(hwndLB, LB_ADDSTRING, 0, (LPARAM)str); + if (LB_ERR != index) + { + SendMessageW(hwndLB, LB_SETITEMDATA, index, (LPARAM)cLetter); + + INT idxSelection = (int)(INT_PTR)SendMessageW(hwndLB, LB_GETCURSEL, 0,0); + if (LB_ERR == idxSelection && cLetter == g_config->ReadInt(L"last_drive", cLetter)) + { + if (LB_ERR != SendMessageW(hwndLB, LB_SETCURSEL, index, 0L)) + { + UpdateDriveInfo(hwndDlg, cLetter); + } + } + + // request unitinfo + DM_UNITINFO_PARAM *pui = (DM_UNITINFO_PARAM*)calloc(1, sizeof(DM_UNITINFO_PARAM)); + if (pui) + { + pui->header.callback = (INT_PTR)hwndDlg; + pui->header.uMsg = msgNotify; + pui->header.cLetter = cLetter; + pui->header.fnFree = FreeAsyncParam; + DriveManager_GetUnitInfo(pui); + } + } + } +} + +static INT GetListBoxIndex(HWND hwndLB, CHAR cLetter) +{ + wchar_t str[] = {cLetter, 0x00}; + return (cLetter && hwndLB) ? (INT)SendMessageW(hwndLB, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)str) : LB_ERR; +} + +static void Drive_OnRemoved(HWND hwndDlg, CHAR cLetter) +{ + HWND hwndLB = GetDlgItem(hwndDlg, IDC_LIST_DRIVES); + + if (IsWindow(hwndLB)) + { + INT index = GetListBoxIndex(hwndLB, cLetter); + if (LB_ERR != index) SendMessageW(hwndLB, LB_DELETESTRING, (WPARAM)index, 0L); + } +} + +static void GetInfo_Completed(HWND hwndDlg, DM_NOTIFY_PARAM *phdr) +{ + wchar_t szBuffer[256] = {0}; + + DM_UNITINFO_PARAM *pui = NULL; + DM_UNITINFO2_PARAM *pui2 = NULL; + DM_DISCINFOEX_PARAM *pdi = NULL; + DM_DISCINFO2_PARAM *pdi2 = NULL; + + switch(phdr->opCode) + { + case DMOP_UNITINFO: + pui = (DM_UNITINFO_PARAM*)phdr; + if (0 == phdr->result) + { + HWND hwndLB = GetDlgItem(hwndDlg, IDC_LIST_DRIVES); + if (hwndLB) + { + INT idxLB = GetListBoxIndex(hwndLB, phdr->cLetter); + if (LB_ERR != idxLB) + { + DWORD data = MAKELONG(phdr->cLetter, pui->dwType); + if (data != (DWORD)SendMessage(hwndLB ,LB_GETITEMDATA, idxLB, 0)) + { + if (LB_ERR != SendMessageW(hwndLB, LB_SETITEMDATA, idxLB, (LPARAM)data)) + { + RECT rc; + SendMessageW(hwndLB, LB_GETITEMRECT, idxLB, (LPARAM)&rc); + InvalidateRect(hwndLB, &rc, FALSE); + UpdateWindow(hwndLB); + } + } + } + } + if (activeDrive == phdr->cLetter && pui->pszDesc) SetDlgItemTextA(hwndDlg, IDC_LBL_DRIVE_DESCRIPTION_VAL, (pui->cchDesc > 0) ? pui->pszDesc : ""); + } + break; + case DMOP_UNITINFO2: + pui2 = (DM_UNITINFO2_PARAM*)phdr; + if (0 == phdr->result && activeDrive == phdr->cLetter) + { + SetDlgItemTextW(hwndDlg, IDC_LBL_DRIVE_BUS_VAL, Drive_GetBusTypeString(pui2->dwBusType)); + szBuffer[0] = 0x00; + for (int i = 0; i < pui2->nTypes; i++) + { + if (0 != i) StringCchCatW(szBuffer, sizeof(szBuffer)/sizeof(wchar_t), L", "); + StringCchCatW(szBuffer, sizeof(szBuffer)/sizeof(wchar_t), Drive_GetTypeString(pui2->pdwTypes[i])); + } + SetDlgItemTextW(hwndDlg, IDC_LBL_DRIVE_TYPES_VAL, szBuffer); + } + break; + case DMOP_DISCINFO: + pdi = (DM_DISCINFOEX_PARAM*)phdr; + if (0 == phdr->result && activeDrive == phdr->cLetter) + { + StringCchPrintfW(szBuffer, sizeof(szBuffer)/sizeof(wchar_t), + WASABI_API_LNGSTRINGW(IDS_X_OF_X_SECTORS_FREE), + pdi->dwFree, pdi->dwUsed + pdi->dwFree); + SetDlgItemTextW(hwndDlg, IDC_LBL_MEDIUM_CAPACITY_VAL, szBuffer); + SetDlgItemInt(hwndDlg, IDC_LBL_MEDIUM_TRACKN_VAL, pdi->dwTracks, FALSE); + SetDlgItemText(hwndDlg, IDC_LBL_MEDIUM_ERASEABLE_VAL, WASABI_API_LNGSTRINGW((pdi->bErasable) ? IDS_YES : IDS_NO)); + SetDlgItemText(hwndDlg, IDC_LBL_MEDIUM_RECORDABLE_VAL, WASABI_API_LNGSTRINGW((Medium_IsRecordableType(pdi->dwMediumType)) ? IDS_YES : IDS_NO)); + SetDlgItemText(hwndDlg, IDC_LBL_MEDIUM_ADDINFO_VAL, Medium_GetTypeString(pdi->dwMediumType)); + SetDlgItemText(hwndDlg, IDC_LBL_MEDIUM_FORMAT_VAL, Medium_GetFormatString(pdi->dwMediumFormat)); + } + break; + case DMOP_DISCINFO2: + pdi2 = (DM_DISCINFO2_PARAM*)phdr; + if (0 == phdr->result && activeDrive == phdr->cLetter) + { + SetDlgItemTextW(hwndDlg, IDC_LBL_MEDIUM_DISC_VAL, Medium_GetPhysicalTypeString(pdi2->dwMediumEx)); + } + break; + } +} + +static void View_OnPluginNotify(HWND hwndDlg, WORD wCode, INT_PTR param) +{ + switch(wCode) + { + case DMW_DRIVEADDED: Drive_OnAdded(hwndDlg, (CHAR)param); break; + case DMW_DRIVEREMOVED: Drive_OnRemoved(hwndDlg, (CHAR)param); break; + case DMW_MEDIUMARRIVED: + case DMW_MEDIUMREMOVED: if ((CHAR)param == activeDrive) UpdateDriveInfo(hwndDlg, activeDrive); break; + case DMW_OPCOMPLETED: + SendMessage(hwndDlg, WM_SIZE, 0, 0); + GetInfo_Completed(hwndDlg, (DM_NOTIFY_PARAM*)param); + break; + } +} + +static INT_PTR ListBox_OnKeyPressed(HWND hwndDlg, HWND hwndLB, WORD wKey, INT iCurret) +{ + switch(wKey) + { + case VK_F5: DriveManager_Update(TRUE); return -2; + case VK_SPACE: + PostMessageW(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_LIST_DRIVES,LBN_DBLCLK), (LPARAM)hwndLB); + return -2; + } + if (wKey >= 'A' && wKey <= 'Z') + { + INT index = GetListBoxIndex(hwndLB, (CHAR)wKey); + return (LB_ERR != index) ? index : -2; + } + + return -1; // do default +} + +INT_PTR CALLBACK view_ripburnDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + INT_PTR a; + + if (uMsg == WM_CTLCOLORSTATIC ) + { + a = LabelColoring((HDC)wParam, (HWND) lParam); + if (a) return a; + } + + a = driveListBox->HandleMsgProc(uMsg,wParam,lParam); if (a) return a; + a = dialogSkinner.Handle(hwndDlg,uMsg,wParam,lParam); if (a) return a; + + switch(uMsg) + { + case WM_INITDIALOG: + ripburn_OnInitDialog(hwndDlg); + break; + case WM_DISPLAYCHANGE: + ripburn_OnDisplayChanges(hwndDlg); + break; + case WM_SIZE: + if (wParam != SIZE_MINIMIZED) + { + childSizer.Resize(hwndDlg,ripburn_rlist,sizeof(ripburn_rlist)/sizeof(ripburn_rlist[0])); + ripburn_OnSize(hwndDlg, LOWORD(lParam), HIWORD(lParam)); + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_LIST_DRIVES: + if (HIWORD(wParam) == LBN_SELCHANGE) + { + INT index = (int)(INT_PTR)SendMessage((HWND)lParam, LB_GETCURSEL, 0,0); + DWORD data = (LB_ERR != index) ? (DWORD)SendMessage((HWND)lParam ,LB_GETITEMDATA, index, 0) : 0; + if (data) UpdateDriveInfo(hwndDlg, (CHAR)(0xFF & data)); + } + else if (HIWORD(wParam) == LBN_DBLCLK) + { + INT index = (int)(INT_PTR)SendMessage((HWND)lParam, LB_GETCURSEL, 0,0); + DWORD data = (LB_ERR != index) ? (DWORD)SendMessage((HWND)lParam ,LB_GETITEMDATA, index, 0) : 0; + HNAVITEM hItem = (data) ? Plugin_GetNavItemFromLetter((CHAR)(0xFF & data)) : NULL; + if (hItem) MLNavItem_Select(plugin.hwndLibraryParent, hItem); + } + break; + case IDC_BTN_REFRESH: + if (HIWORD(wParam) == BN_CLICKED) DriveManager_Update(TRUE); + break; + } + break; + case WM_PAINT: + { + int tab[] = { IDC_LIST_DRIVES | DCW_SUNKENBORDER, + IDC_LBL_DRIVES | DCW_SUNKENBORDER, + IDC_LBL_INFO_DRIVE | DCW_SUNKENBORDER, + IDC_LBL_INFO_MEDIUM | DCW_SUNKENBORDER}; + dialogSkinner.Draw(hwndDlg, tab, 4); + } + return 0; + case WM_DESTROY: + ripburn_OnDestroy(hwndDlg); + break; + case WM_ERASEBKGND: + return 0; + case WM_VKEYTOITEM: + return ListBox_OnKeyPressed(hwndDlg, (HWND)lParam, LOWORD(wParam), HIWORD(wParam)); + } + if (msgNotify == uMsg) + View_OnPluginNotify(hwndDlg, (WORD)wParam, (INT_PTR)lParam); + + return FALSE; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_disc/view_wait.cpp b/Src/Plugins/Library/ml_disc/view_wait.cpp new file mode 100644 index 00000000..17a8fa6f --- /dev/null +++ b/Src/Plugins/Library/ml_disc/view_wait.cpp @@ -0,0 +1,140 @@ +#include "main.h" +#include "./resource.h" +#include "../nu/DialogSkinner.h" + +#include <windowsx.h> + +static HBRUSH hbBack = NULL; +#define TIMER_SHOWTEXT_ID 1985 +#define TIMER_SHOWTEXT_DELAY 1000 + +static INT_PTR WINAPI DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +// public function +HWND CreateWaitWindow(HWND hwndParent, CHAR cLetter) +{ + return WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_WAIT, hwndParent, DlgProc, (LPARAM)cLetter); +} + +static void CALLBACK Window_TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + switch(idEvent) + { + case TIMER_SHOWTEXT_ID: + KillTimer(hwnd, TIMER_SHOWTEXT_ID); + SetDlgItemTextW(hwnd, IDC_LBL_TEXT, WASABI_API_LNGSTRINGW(IDS_READINGDISC)); + break; + } +} + +static INT_PTR Window_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) +{ + SendMessageW(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_BTN_SHOWINFO, BN_EX_GETTEXT), (LPARAM)GetDlgItem(hwnd, IDC_BTN_SHOWINFO)); + SetTimer(hwnd, TIMER_SHOWTEXT_ID, TIMER_SHOWTEXT_DELAY, Window_TimerProc); + return 0; +} + +static void Window_OnDestroy(HWND hwnd) +{ + if (hbBack) + { + DeleteObject(hbBack); + hbBack = NULL; + } +} + +static void Window_OnDisplayChange(HWND hwnd, INT dpi, INT resX, INT resY) +{ + if (hbBack) + { + DeleteObject(hbBack); + hbBack = NULL; + } + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN); +} + +static void Window_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp) +{ + HWND hwndCtrl; + RECT rw; + + hwndCtrl = GetDlgItem(hwnd, IDC_BTN_SHOWINFO); + if(hwndCtrl) + { + GetWindowRect(hwndCtrl, &rw); + OffsetRect(&rw, -rw.left, -rw.top); + SetWindowPos(hwndCtrl, NULL, pwp->cx - rw.right, pwp->cy - rw.bottom, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS); + } + + hwndCtrl = GetDlgItem(hwnd, IDC_LBL_TEXT); + if(hwndCtrl) + { + GetWindowRect(hwndCtrl, &rw); + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2); + SetWindowPos(hwndCtrl, NULL, 0, 0, pwp->cx - rw.left - 2, pwp->cy - 22 - rw.top, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS); + } + if (0 == (SWP_NOREDRAW & pwp->flags)) + { + InvalidateRect(hwnd, NULL, TRUE); + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); + } +} + +static void Window_OnCommand(HWND hwnd, INT eventId, INT ctrlId, HWND hwndCtrl) +{ + switch(ctrlId) + { + case IDC_BTN_SHOWINFO: + switch(eventId) + { + case BN_CLICKED: + SendMessageW(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(ctrlId, eventId),(LPARAM)hwndCtrl); + break; + } + break; + } +} + +static HBRUSH Window_OnStaticColor(HWND hwnd, HDC hdc) +{ + if (!hbBack) hbBack = CreateSolidBrush(dialogSkinner.Color(WADLG_ITEMBG)); + SetTextColor(hdc, dialogSkinner.Color(WADLG_ITEMFG)); + SetBkColor(hdc, dialogSkinner.Color(WADLG_ITEMBG)); + return hbBack; +} + +static void Window_OnPaint(HWND hwnd) +{ + int tab[] = { IDC_LBL_TEXT | DCW_SUNKENBORDER}; + dialogSkinner.Draw(hwnd, tab, 1); +} + +static void Window_OnQueryInfo(HWND hwnd) +{ + HWND hwndParent; + hwndParent = GetParent(hwnd); + if (hwndParent) SendMessageW(hwndParent, WM_SHOWFILEINFO, (WPARAM)WISF_NORMAL, (LPARAM)L""); +} + +static INT_PTR WINAPI DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + INT_PTR result; + + if (WM_CTLCOLORSTATIC == uMsg) return (INT_PTR)Window_OnStaticColor(hwnd, (HDC)wParam); + result = dialogSkinner.Handle(hwnd, uMsg, wParam, lParam); + if (result) return result; + + switch(uMsg) + { + case WM_INITDIALOG: return (INT_PTR)Window_OnInitDialog(hwnd, (HWND)wParam, lParam); + case WM_DESTROY: Window_OnDestroy(hwnd); break; + case WM_DISPLAYCHANGE: Window_OnDisplayChange(hwnd, (INT)wParam, LOWORD(lParam), HIWORD(lParam)); break; + case WM_WINDOWPOSCHANGED: Window_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); break; + case WM_COMMAND: Window_OnCommand(hwnd, HIWORD(wParam), LOWORD(wParam), (HWND)lParam); break; + case WM_PAINT: Window_OnPaint(hwnd); break; + case WM_QUERYFILEINFO: Window_OnQueryInfo(hwnd); break; + } + return 0; +}
\ No newline at end of file |