#include "master.h" #include #include #include #include #include #include #include #include #include "playlist.h" #include "misc.h" #include "stream.h" #include "gui.h" #include "metaparse.h" #include "comfunct/comfunct.h" DWORD WINAPI OpenPlaylistFile(LPVOID lpThreadParams) { OPENFILENAME ofn = {sizeof(OPENFILENAME), 0}; TCHAR szMyMusicDir[MAX_PATH] = TEXT(""); HWND hwnd = GetAPWindow(); PLAYLISTDATA* pld = (PLAYLISTDATA*)lpThreadParams; GetMyMusicDir(hwnd, szMyMusicDir); ofn.hwndOwner = hwnd; ofn.lpstrFilter = GetLocalText(152); ofn.lpstrFile = pld->szPlaylistPath; ofn.nFilterIndex = 4; ofn.lpstrTitle = GetLocalText(46); ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_NONETWORKBUTTON | OFN_HIDEREADONLY; ofn.lpstrDefExt = TEXT("m3u"); ofn.lpstrInitialDir = szMyMusicDir; if(GetOpenFileName(&ofn)) { if(InvokePlaylist(pld) == 1) { ErrorMessage(GetLocalText(47)); SetStatus(hwnd, IDI_STATUS, 0, GetLocalText(7)); return 1; } } else if(CommDlgExtendedError() == 0) { SetStatus(hwnd, IDI_STATUS, 0, GetLocalText(7)); return 2; } return 0; } DWORD WINAPI InvokePlaylist(LPVOID lpParams) { PLAYLISTDATA* pld = (PLAYLISTDATA*)lpParams; int PlaylistType = GetPlaylistType(pld->szPlaylistPath); CoInitialize(NULL); if(PlaylistType == PLAYLIST_ERROR) { return 1; } else { switch(PlaylistType) { case PLAYLIST_ASX: { LPTSTR szTempPlaylistName = ASXToXML(pld->szPlaylistPath); memcpy(pld->szPlaylistPath, szTempPlaylistName, (MAX_PATH * sizeof(TCHAR))); free(szTempPlaylistName); if(ASXLoad(pld) == false) { CoUninitialize(); return 1; } } break; case PLAYLIST_M3U: { if(M3ULoad(pld) == false) { CoUninitialize(); return 1; } } break; case PLAYLIST_WPL: { if(WPLLoad(pld) == false) { CoUninitialize(); return 1; } } break; } StartPlaylist(pld, GetAPWindow()); return 0; } } int GetPlaylistType(LPTSTR szFileName) { BYTE FileData[2] = {0}; /* We only need the first two chars to differentiate between file types */ HANDLE hFile = NULL; DWORD dwBytesRead = 0; hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == NULL || hFile == INVALID_HANDLE_VALUE) { return PLAYLIST_ERROR; } ReadFile(hFile, &FileData[0], 2, &dwBytesRead, NULL); CloseHandle(hFile); if(FileData[0] == TEXT('#')) { return PLAYLIST_M3U; } else if(FileData[0] == TEXT('<')) { if(tolower(FileData[1]) == TEXT('a')) { return PLAYLIST_ASX; } else if (FileData[1] == TEXT('?')) { return PLAYLIST_WPL; } return PLAYLIST_ERROR; } else if(_tcsicmp(PathFindExtension(szFileName), TEXT("m3u")) == 0) { return PLAYLIST_M3U; } else return PLAYLIST_ERROR; } bool M3ULoad(PLAYLISTDATA* pld) { /* File ref's are on every non-blank line not starting with a # */ char szThisFileLine[1000] = ""; FILE* M3UFile = NULL; unsigned long lFilesInPlaylist = 0, lLoopCount = 0; HWND hPlaylistItems = GetDlgItem(GetAPWindow(), IDI_PLAYLIST_VIEW); DWORD dwThreadId = 0; M3UFile = _tfopen(pld->szPlaylistPath, TEXT("r")); if(M3UFile == NULL) { ErrorMessage(GetLocalText(48)); return false; } while(fgets(szThisFileLine, 1000, M3UFile)) { if(szThisFileLine[0] == '#' || szThisFileLine[0] == '\r' || szThisFileLine[0] == '\n' || szThisFileLine[0] == '.') /* we don't need comment or blank lines or relative paths */ { continue; } ++lFilesInPlaylist; /* First we need to know how many files the playlist contains references to */ } rewind(M3UFile); pld->PlaylistItems = malloc(lFilesInPlaylist * sizeof(TCHAR*)); pld->lNumOfFilesinPlaylist = lFilesInPlaylist; for(; lLoopCount < lFilesInPlaylist; ++lLoopCount) { while(fgets(szThisFileLine, 1000, M3UFile)) { WCHAR wszWideFileLine[1000] = L""; size_t s_tLineLength = strlen(szThisFileLine); if(szThisFileLine[0] == '#' || szThisFileLine[0] == '\r') /* again we don't need comment or blank lines */ { continue; } szThisFileLine[(s_tLineLength - 1)] = '\0'; if(PathIsURLA(szThisFileLine) == FALSE && PathFileExistsA(szThisFileLine) == FALSE) { continue; } pld->PlaylistItems[lLoopCount] = malloc(s_tLineLength * sizeof(TCHAR)); #ifdef UNICODE MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szThisFileLine, -1, wszWideFileLine, (int)(s_tLineLength * 2)); /*_snwprintf(pld->PlaylistItems[lLoopCount], (int)s_tLineLength, L"%s", wszWideFileLine);*/ wcscpy(pld->PlaylistItems[lLoopCount], wszWideFileLine); #else /*_snprintf(pld->PlaylistItems[lLoopCount], s_tLineLength, "%s", szThisFileLine);*/ strcpy(pld->PlaylistItems[lLoopCount], szThisFileLine); #endif break; /* So we go back to the for loop and increment lLoopCount, otherwise we keep overwriting the first element */ } /* end of while loop */ } /* end of for loop */ fclose(M3UFile); CloseHandle(CreateThread(NULL, 0, BuildPlaylistView, (LPVOID)pld, 0, &dwThreadId)); return true; } bool WPLLoad(PLAYLISTDATA* pld) { /* File ref's are in field body->seq->media, attribute src */ IXMLDOMDocument2 *pPlaylist = NULL; IXMLDOMNodeList *pNodes = NULL; long lNoOfItems = 0; BSTR bstrNodeName; pPlaylist = LoadXML(pld->szPlaylistPath); if(pPlaylist == NULL) { return false; } bstrNodeName = SysAllocString(L"media"); pPlaylist->lpVtbl->getElementsByTagName(pPlaylist, bstrNodeName, &pNodes); pNodes->lpVtbl->get_length(pNodes, &lNoOfItems); SysFreeString(bstrNodeName); XMLToPlaylist(pld, L"src", pNodes, lNoOfItems); SAFE_RELEASE(pPlaylist); SAFE_RELEASE(pNodes); return true; } /* bool ASXLoad(PLAYLISTDATA* pld) { /* File ref's are in field entry->SourceUrl IXMLDOMDocument2 *pPlaylist = NULL; IXMLDOMNodeList *pNodes = NULL; IXMLDOMNamedNodeMap *pAttributes = NULL; IXMLDOMNode *pThisEntry = NULL, *pAttributeProperty = NULL; BSTR bstrNodeName, bstrAttributeName = SysAllocString(L"Name"), bstr; long lNoOfItems = 0, loop = 0, lFileCount = 0; DWORD dwStartTime = 0, dwEndTime = 0, dwResult = 0; char szBuf[200] = ""; pPlaylist = LoadXML(pld->szPlaylistPath); if(pPlaylist == NULL) { return false; } bstrNodeName = SysAllocString(L"Param"); pPlaylist->lpVtbl->getElementsByTagName(pPlaylist, bstrNodeName, &pNodes); pNodes->lpVtbl->get_length(pNodes, &lNoOfItems); timeBeginPeriod(1); dwStartTime = timeGetTime(); for(; loop < lNoOfItems; loop++) { pNodes->lpVtbl->get_item(pNodes, loop, &pThisEntry); pThisEntry->lpVtbl->get_attributes(pThisEntry, &pAttributes); pAttributes->lpVtbl->getNamedItem(pAttributes, bstrAttributeName, &pAttributeProperty); pAttributeProperty->lpVtbl->get_text(pAttributeProperty, &bstr); if(wcscmp(bstr, L"SourceURL") == 0) { ++lFileCount; } SAFE_RELEASE(pAttributeProperty); SAFE_RELEASE(pAttributes); SAFE_RELEASE(pThisEntry); SysFreeString(bstr); } dwEndTime = timeGetTime(); dwResult = dwEndTime - dwStartTime; sprintf(szBuf, "The calculation took %d milliseconds", dwResult); ErrorMessageA(szBuf); timeEndPeriod(1); SysFreeString(bstrAttributeName); SysFreeString(bstrNodeName); XMLToPlaylist(pld, L"href", pNodes, lNoOfItems); SAFE_RELEASE(pNodes); SAFE_RELEASE(pPlaylist); return true; }*/ bool ASXLoad(PLAYLISTDATA* pld) { /* File ref's are in field entry->SourceUrl */ IXMLDOMDocument2 *pPlaylist = NULL; IXMLDOMNodeList *pNodes = NULL; BSTR bstrNodeName; long lNoOfItems = 0; pPlaylist = LoadXML(pld->szPlaylistPath); if(pPlaylist == NULL) { return false; } bstrNodeName = SysAllocString(L"Ref"); pPlaylist->lpVtbl->getElementsByTagName(pPlaylist, bstrNodeName, &pNodes); pNodes->lpVtbl->get_length(pNodes, &lNoOfItems); SysFreeString(bstrNodeName); XMLToPlaylist(pld, L"href", pNodes, lNoOfItems); SAFE_RELEASE(pNodes); SAFE_RELEASE(pPlaylist); return true; } void XMLToPlaylist(PLAYLISTDATA* pld, LPWSTR szAttribute, IXMLDOMNodeList* pParentNodes, unsigned long lNoOfItems) { IXMLDOMNamedNodeMap *pAttributes = NULL; IXMLDOMNode *pThisEntry = NULL, *pAttributeProperty = NULL; unsigned long lLoopCounter = 0L; DWORD dwThreadId = 0; HWND hPlaylistItems = GetDlgItem(GetAPWindow(), IDI_PLAYLIST_VIEW); pld->PlaylistItems = malloc(lNoOfItems * sizeof(TCHAR*)); for(; lLoopCounter < lNoOfItems; lLoopCounter++) { BSTR bstr; char* szNarrowText = NULL; size_t s_tStrlen = 0; pParentNodes->lpVtbl->get_item(pParentNodes, lLoopCounter, &pThisEntry); /* Get the [loop]'th media node and put into pThisEntry */ pThisEntry->lpVtbl->get_attributes(pThisEntry, &pAttributes); /* Put its attributes into pAttributes */ bstr = SysAllocString(szAttribute); pAttributes->lpVtbl->getNamedItem(pAttributes, bstr, &pAttributeProperty); /* Get the passed in attribute property and put its reference into pAttributeProperty*/ SysFreeString(bstr); pAttributeProperty->lpVtbl->get_text(pAttributeProperty, &bstr); /* Put the text associated with attribute into the bstr variable */ s_tStrlen = (wcslen(bstr) + 1); /* wcslen returns the number of chars not bytes and BSTR's are always wide strings for us */ #ifndef UNICODE szNarrowText = ASCIIConversion(bstr); pld->PlaylistItems[lLoopCounter] = malloc(s_tStrlen); _snprintf(pld->PlaylistItems[lLoopCounter], s_tStrlen, "%s", szNarrowText); //strcpy(pld->PlaylistItems[lLoopCounter], szNarrowText); FreePointer(szNarrowText); #else pld->PlaylistItems[lLoopCounter] = malloc(s_tStrlen * sizeof(WCHAR)); _snwprintf(pld->PlaylistItems[lLoopCounter], s_tStrlen, L"%s", bstr); //wcscpy(pld->PlaylistItems[lLoopCounter], bstr); #endif SysFreeString(bstr); SAFE_RELEASE(pAttributeProperty); SAFE_RELEASE(pAttributes); SAFE_RELEASE(pThisEntry); } pld->lNumOfFilesinPlaylist = lLoopCounter; CloseHandle(CreateThread(NULL, 0, BuildPlaylistView, (LPVOID)pld, 0, &dwThreadId)); return; } IXMLDOMDocument2* LoadXML(LPTSTR szPlaylistPath) { IXMLDOMDocument2 *pPlaylist = NULL; VARIANT_BOOL bSuccess = VARIANT_FALSE; VARIANT var; HRESULT hr = 0; WCHAR* wideszPlaylistPath = NULL; hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (void**)&pPlaylist); if(FAILED(hr)) { HRErrorInfo(hr); return NULL; } VariantInit(&var); #ifndef UNICODE wideszPlaylistPath = UnicodeConversion(szPlaylistPath); V_BSTR(&var) = SysAllocString(wideszPlaylistPath); FreePointer(wideszPlaylistPath); #else V_BSTR(&var) = SysAllocString(szPlaylistPath); #endif V_VT(&var) = VT_BSTR; hr = pPlaylist->lpVtbl->load(pPlaylist, var, &bSuccess); if(bSuccess != VARIANT_TRUE || FAILED(hr)) { SAFE_RELEASE(pPlaylist); HRErrorInfo(hr); VariantClear(&var); return NULL; } VariantClear(&var); // calls SysFreeString internally return pPlaylist; } LPTSTR ASXToXML(LPTSTR szOldFileName) { HANDLE hOldFile = NULL, hAsxmlFile = NULL; BYTE* byFileData = NULL; BYTE* byCorrectedFileData = NULL; DWORD dwFileSize = 0, dwBytesRead = 0, dwBytesWritten = 0; DWORD loop = 0, dwCorrectedByteCount = 0; int iAmpTextCount = 0, iAmpCharSize = 0; const char byAmpersandText[] = "&"; TCHAR* szNewFileName = malloc((MAX_PATH * sizeof(TCHAR))); LPTSTR IsValidXML = NULL; iAmpCharSize = sizeof(byAmpersandText) - 1; /* Don't want to count the NULL */ memcpy(szNewFileName, szOldFileName, (MAX_PATH * sizeof(TCHAR))); IsValidXML = _tcsstr(PathFindExtension(szOldFileName), TEXT("ml")); if(IsValidXML != NULL) { return szNewFileName; } _tcscat(szNewFileName, TEXT("ml")); if(PathFileExists(szNewFileName) == TRUE) { return szNewFileName; } hOldFile = CreateFile(szOldFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); hAsxmlFile = CreateFile(szNewFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); dwFileSize = GetFileSize(hOldFile, NULL); byFileData = malloc(dwFileSize); byCorrectedFileData = malloc(dwFileSize * 2); memset(byCorrectedFileData, 0, (dwFileSize * 2)); ReadFile(hOldFile, &byFileData[0], dwFileSize, &dwBytesRead, NULL); CloseHandle(hOldFile); for(; loop < dwFileSize; ++loop) // This is definitely not the fastest way to do this, _tcsspn may be an example { if(byFileData[loop] == '&') { for(iAmpTextCount = 0; iAmpTextCount < iAmpCharSize; iAmpTextCount++) { byCorrectedFileData[dwCorrectedByteCount] = byAmpersandText[iAmpTextCount]; ++dwCorrectedByteCount; } } else if ((byFileData[loop] == '\r' || byFileData[loop] == '\n') || (byFileData[loop] >= ' ' && byFileData[loop] <= 'z')) { byCorrectedFileData[dwCorrectedByteCount] = byFileData[loop]; ++dwCorrectedByteCount; } } free(byFileData); WriteFile(hAsxmlFile, &byCorrectedFileData[0], dwCorrectedByteCount, &dwBytesWritten, NULL); free(byCorrectedFileData); CloseHandle(hAsxmlFile); return szNewFileName; } void TogglePlaylistMenu(HWND hwnd, bool bState) { HMENU hParent = GetMenu(hwnd), hFileMenu = NULL; hFileMenu = GetSubMenu(hParent, FILE_MENU); if(bState == true) { EnableMenuItem(hParent, PLAYLIST_MENU, MF_BYPOSITION | MF_ENABLED); } else { EnableMenuItem(hParent, PLAYLIST_MENU, MF_BYPOSITION | MF_GRAYED); } DrawMenuBar(hwnd); return; } unsigned long GetRandomTrack(PLAYLISTDATA* pld) { unsigned long lRandomTrack = 0L; srand((UINT)GetTickCount()); if(pld->lNumOfFilesinPlaylist == 1L) { return 0L; } do { #if !defined(_MSC_VER) || _MSC_VER < 1400 /* If we're compiling in something other than VS2005 we still have to use the old random number generator */ lRandomTrack = (unsigned long)(pld->lNumOfFilesinPlaylist * rand()/(RAND_MAX + 1.0)); #elif defined(_MSC_VER) && _MSC_VER >= 1400 /* If you're compiling with VS2005 you can use the rand_s function for a better spread of random numbers */ rand_s((UINT*)&lRandomTrack); lRandomTrack = lRandomTrack % pld->lNumOfFilesinPlaylist; #endif } while (lRandomTrack == pld->lCurrentPlayingFile); /* Keep getting a random number until it's not the same as the number of the currently playing file */ return lRandomTrack; } DWORD WINAPI RawDataToPlaylist(LPVOID lpParam) { RAWDATA* rd = (RAWDATA*)lpParam; TCHAR szDirectory[MAX_PATH] = TEXT(""); unsigned long lLoopCount = 0L, lNumFiles = rd->lNumFiles; size_t s_tDirectorySize = (_tcslen(rd->szPlaylist) + 1); TCHAR* szBufferPointer = NULL; TCHAR szIntermediateBuffer[MAX_PATH] = TEXT(""); size_t s_tStrlen = 0; DWORD dwThreadId = 0; HWND hPlaylistItems = GetDlgItem(rd->hwnd, IDI_PLAYLIST_VIEW); _tcscpy(szDirectory, rd->szPlaylist); rd->pld->PlaylistItems = malloc(lNumFiles * sizeof(TCHAR*)); _tcscat(szDirectory, TEXT("\\")); szBufferPointer = rd->szPlaylist + s_tDirectorySize; SendMessage(hPlaylistItems, LB_INITSTORAGE, (WPARAM)lNumFiles, (LPARAM)MAX_PATH); for(; lLoopCount < lNumFiles; lLoopCount++) { _tcscpy(szIntermediateBuffer, szDirectory); _tcscat(szIntermediateBuffer, szBufferPointer); s_tStrlen = (_tcslen(szIntermediateBuffer) + sizeof(TCHAR)); rd->pld->PlaylistItems[lLoopCount] = malloc(s_tStrlen * sizeof(TCHAR)); _tcscpy(rd->pld->PlaylistItems[lLoopCount], szIntermediateBuffer); szBufferPointer = _tcschr((szBufferPointer + sizeof(TCHAR)), TEXT('\0')) + 1; /* Set the pointer to the character after the next NULL */ } rd->pld->lNumOfFilesinPlaylist = lNumFiles; CloseHandle(CreateThread(NULL, 0, BuildPlaylistView, (LPVOID)rd->pld, 0, &dwThreadId)); StartPlaylist(rd->pld, rd->hwnd); return 0; } void SavePlaylist(HWND hwnd, PLAYLISTDATA* pld) { OPENFILENAME ofn = {0}; TCHAR szFileName[MAX_PATH] = TEXT(""); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.lpstrFilter = GetLocalText(49); ofn.lpstrFile = szFileName; ofn.nFilterIndex = 1; ofn.lpstrTitle = GetLocalText(50); ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_NONETWORKBUTTON | OFN_OVERWRITEPROMPT; ofn.lpstrDefExt = TEXT("m3u"); if(GetSaveFileName(&ofn)) { SavePlaylistAsM3U(pld, szFileName); } return; } void SavePlaylistAsM3U(PLAYLISTDATA* pld, LPCTSTR szFileName) { HANDLE hFile = NULL; DWORD dwBytesWritten = 0; /* Again uncomment this for internationalisation TCHAR* szFileHeader = GetLocalText(number); char* szNarrowHeader = NULL; */ const char szFileHeader[] = "#EXTM3U Playlist written by AudioPlayer\r\n\r\n"; const char szLineEndings[] = "\r\n"; unsigned long lLoopCount = 0L; char* szConversion = NULL; size_t s_tBufferLength = 0; int iBufferLocation = 0; char* szBuffer = malloc((MAX_PATH * pld->lNumOfFilesinPlaylist) + sizeof(szFileHeader)); /* When we do the GetLocalText's uncomment this char* szBuffer = NULL; #ifdef UNICODE szNarrowHeader = ASCIIConversion(szFileHeader); #else szNarrowHeader = szFileHeader; #endif szBuffer = malloc((MAX_PATH * pld->lNumOfFilesinPlaylist) + strlen(szNarrowHeader) + 1); */ hFile = CreateFile(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == NULL || hFile == INVALID_HANDLE_VALUE) { ErrorInfo(); ErrorMessage(GetLocalText(51)); free(szBuffer); return; } /* again uncomment strcpy(szBuffer, szNarrowHeader); iBufferLocation = strlen(szNarrowHeader); /* Minus 1 because we don't want to count the terminating null */ strcpy(szBuffer, szFileHeader); iBufferLocation = (sizeof(szFileHeader) - 1); /* Minus 1 because we don't want to count the terminating null */ for(; lLoopCount < pld->lNumOfFilesinPlaylist; lLoopCount++) { #ifdef UNICODE szConversion = ASCIIConversion(pld->PlaylistItems[lLoopCount]); s_tBufferLength = strlen(szConversion); strcat(szBuffer, szConversion); iBufferLocation += (int)s_tBufferLength; FreePointer(szConversion); #else s_tBufferLength = strlen(pld->PlaylistItems[lLoopCount]); strcat(szBuffer, pld->PlaylistItems[lLoopCount]); iBufferLocation += (int)s_tBufferLength; #endif strcat(szBuffer, szLineEndings); iBufferLocation += (sizeof(szLineEndings) - 1); /* Don't count the terminating NULL again */ } WriteFile(hFile, szBuffer, iBufferLocation, &dwBytesWritten, NULL); free(szBuffer); CloseHandle(hFile); /* When we do the GetLocalText's uncomment this #ifdef UNICODE FreePointer(szNarrowHeader); #endif */ return; } void StartPlaylist(PLAYLISTDATA* pld, HWND hwnd) { if(pld->bShuffle == true) { pld->lCurrentPlayingFile = GetRandomTrack(pld); } else pld->lCurrentPlayingFile = 0; TogglePlaylistMenu(hwnd, true); SetStatus(hwnd, IDI_STATUS, 0, GetLocalText(7)); ProcessFile(hwnd, IsIconic(hwnd), pld->PlaylistItems[pld->lCurrentPlayingFile], pld); return; } void AddFileToPlaylistView(HWND hPlaylistItems, TCHAR* szFile, unsigned long lPos) { IWMMetadataEditor* pWMEdit = NULL; WCHAR* wszTitle = NULL, *wszFile = NULL; LVITEM lvi[2] = {{0}, {0}}; lvi[0].mask = LVIF_TEXT | LVIF_PARAM; lvi[0].iItem = lPos; lvi[0].iSubItem = 0; lvi[0].lParam = lPos; #ifdef UNICODE pWMEdit = CreateReader(szFile); #else wszFile = UnicodeConversion(szFile); pWMEdit = CreateReader(wszFile); #endif wszTitle = GetAttribute(pWMEdit, g_wszWMTitle); if(wszTitle == NULL || (wcscmp(wszTitle, L"") == 0)) { #ifdef UNICODE WCHAR* wszFileTitle = PathFindFileName(szFile); PathRemoveExtension(wszFileTitle); lvi[0].pszText = wszFileTitle; #else char* szFileTitle = PathFindFileName(szFile); PathRemoveExtension(szFileTitle); lvi[0].pszText = szFileTitle; #endif ListView_InsertItem(hPlaylistItems, &lvi[0]); } else { #ifdef UNICODE lvi[0].pszText = wszTitle; #else lvi[0].pszText = ASCIIConversion(wszTitle); #endif ListView_InsertItem(hPlaylistItems, &lvi[0]); free(wszTitle); #ifndef UNICODE FreePointer(lvi[0].pszText); #endif } #ifndef UNICODE FreePointer(wszFile); #endif pWMEdit->lpVtbl->Close(pWMEdit); SAFE_RELEASE(pWMEdit); return; } int CALLBACK CompareListItems(LPARAM lParamItem1, LPARAM lParamItem2, LPARAM lParamHWND) { LVFINDINFO lvf[2] = {{LVFI_PARAM, 0}, {LVFI_PARAM, 0}}; LVITEM lvi[2] = {{0}, {0}}; TCHAR szText1[MAX_PATH] = TEXT(""), szText2[MAX_PATH] = TEXT(""); lvi[0].pszText = szText1; lvi[0].mask = LVIF_TEXT; lvi[0].cchTextMax = MAX_PATH; lvi[1].pszText = szText2; lvi[1].mask = LVIF_TEXT; lvi[1].cchTextMax = MAX_PATH; lvf[0].lParam = lParamItem1; lvf[1].lParam = lParamItem2; lvi[0].iItem = ListView_FindItem((HWND)lParamHWND, -1, &lvf[0]); lvi[1].iItem = ListView_FindItem((HWND)lParamHWND, -1, &lvf[1]); ListView_GetItem((HWND)lParamHWND, &lvi[0]); ListView_GetItem((HWND)lParamHWND, &lvi[1]); return _tcsicmp(szText1, szText2); } DWORD WINAPI PlaylistSortSupportThread(LPVOID lpParam) { HWND hPlaylistItems = (HWND)lpParam; ListView_SortItems((HWND)lpParam, CompareListItems, (LPARAM)lpParam); return 0; } DWORD WINAPI BuildPlaylistView(LPVOID lpParam) { unsigned long lFile = 0; HWND hwnd = GetAPWindow(); HWND hPlaylistItems = GetDlgItem(hwnd, IDI_PLAYLIST_VIEW); HWND hPlaylistText = GetDlgItem(hwnd, IDI_PLAYLIST_TITLE); MENUITEMINFO mii = {sizeof(MENUITEMINFO), 0}; RECT rc = {0}; HMENU hParentMenu = GetMenu(hwnd), hSubMenu = GetSubMenu(hParentMenu, PLAYLIST_MENU); PLAYLISTDATA* pld = (PLAYLISTDATA*)lpParam; TCHAR szPlaylistTitle[260] = TEXT(""), szTitleCopy[260] = TEXT(""); _tcscpy(szPlaylistTitle, GetLocalText(6)); if(_tcscmp(TEXT(""), pld->szPlaylistPath) != 0) { TCHAR szPlaylistFileName[100] = TEXT(" - "); _tcscat(szPlaylistFileName, PathFindFileName(pld->szPlaylistPath)); _tcscat(szPlaylistTitle, szPlaylistFileName); } _tcscpy(szTitleCopy, szPlaylistTitle); _tcscat(szTitleCopy, GetLocalText(52)); SetWindowText(hPlaylistText, szTitleCopy); ListView_SetItemCount(hPlaylistItems, pld->lNumOfFilesinPlaylist); for(; lFile < pld->lNumOfFilesinPlaylist; ++lFile) { /* AddFileToPlaylistView changes the second parameter so we make a copy of the file's path and send that in instead */ TCHAR szFile[MAX_PATH] = TEXT(""); _tcscpy(szFile, pld->PlaylistItems[lFile]); AddFileToPlaylistView(hPlaylistItems, szFile, lFile); } PlaylistSortSupportThread((LPVOID)hPlaylistItems); SetWindowText(hPlaylistText, szPlaylistTitle); mii.fMask = MIIM_STATE; GetMenuItemInfo(hSubMenu, IDI_PLAYLIST_SHOW, FALSE, &mii); GetWindowRect(hwnd, &rc); if((mii.fState == MFS_CHECKED) && ((rc.right - rc.left) < 400)) { AdjustWindowWidth(hwnd, PLAYLIST_VIEW_WIDTH); } return 0; } void GetPVSelection(HWND hPlaylistItems, LVITEM* lplvi) { lplvi->iItem = ListView_GetSelectionMark(hPlaylistItems); lplvi->iSubItem = 0; ListView_GetItem(hPlaylistItems, lplvi); return; } void FolderFilesToPlaylist(TCHAR* szPattern, PLAYLISTDATA* pld) { WIN32_FIND_DATA wfd = {0}; HANDLE hFile = FindFirstFile(szPattern, &wfd); /* fills wfd with the folder info, not the first file in the folder */ unsigned long lLoopCount = 0; DWORD dwThreadId = 0; TCHAR szFolder[MAX_PATH] = TEXT(""); size_t s_tPatLen = _tcslen(szPattern); memcpy(szFolder, szPattern, s_tPatLen * sizeof(TCHAR)); szFolder[s_tPatLen - 3] = 0; while(FindNextFile(hFile, &wfd) != 0) { TCHAR szFullFileName[MAX_PATH] = TEXT(""); if((wfd.cFileName[0] == TEXT('.')) || (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) /* Again, not interested in any relative directory paths */ { continue; } _tcscpy(szFullFileName, szFolder); _tcscat(szFullFileName, wfd.cFileName); pld->PlaylistItems[lLoopCount] = malloc((_tcslen(szFullFileName) + sizeof(TCHAR)) * sizeof(TCHAR)); _tcscpy(pld->PlaylistItems[lLoopCount], szFullFileName); ++lLoopCount; } FindClose(hFile); StartPlaylist(pld, GetAPWindow()); CloseHandle(CreateThread(NULL, 0, BuildPlaylistView, (LPVOID)pld, 0, &dwThreadId)); return; }