aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Library/ml_disc/cdburn.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/Library/ml_disc/cdburn.cpp')
-rw-r--r--Src/Plugins/Library/ml_disc/cdburn.cpp2155
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;
+}