diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_disc/cdburn.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/Library/ml_disc/cdburn.cpp')
-rw-r--r-- | Src/Plugins/Library/ml_disc/cdburn.cpp | 2155 |
1 files changed, 2155 insertions, 0 deletions
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; +} |