12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454 |
- #define PLUGIN_NAME "Nullsoft Portable Music Player Support"
- #define PLUGIN_VERSION L"2.25"
- #include "main.h"
- #include <windows.h>
- #include <windowsx.h>
- #include <stdio.h>
- #include <shlobj.h>
- #include <shlwapi.h>
- #include "..\..\General\gen_ml/ml.h"
- #include "..\..\General\gen_ml/itemlist.h"
- #include "../winamp/wa_ipc.h"
- #include "nu/ns_wc.h"
- #include "..\..\General\gen_hotkeys/wa_hotkeys.h"
- #include "resource1.h"
- #include "pmp.h"
- #include "DeviceView.h"
- #include "pluginloader.h"
- #include "nu/AutoWide.h"
- #include "api__ml_pmp.h"
- #include "transcoder_imp.h"
- #include <api/service/waservicefactory.h>
- #include "config.h"
- #include "tataki/export.h"
- #include "nu/ServiceWatcher.h"
- #include "..\..\General\gen_ml/ml_ipc_0313.h"
- #include "mt19937ar.h"
- #include "./local_menu.h"
- #include "pmpdevice.h"
- #include "IconStore.h"
- #include "../replicant/nx/nxstring.h"
- #include <strsafe.h>
- #include "../nu/MediaLibraryInterface.h"
- #include <vector>
- #define MAINTREEID 5002
- #define PROGRESSTIMERID 1
- static int init();
- static void quit();
- static INT_PTR PluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3);
- LRESULT CALLBACK DeviceMsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- extern INT_PTR CALLBACK pmp_devices_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
- extern void UpdateDevicesListView(bool softupdate);
- INT_PTR CALLBACK global_config_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
- INT_PTR CALLBACK config_dlgproc_plugins(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
- void UpdateTransfersListView(bool softUpdate, CopyInst * item=NULL);
- static void CALLBACK ProgressTimerTickCb(HWND hwnd, UINT uMsg, UINT_PTR eventId, unsigned long elapsed);
- extern "C" winampMediaLibraryPlugin plugin =
- {
- MLHDR_VER,
- "nullsoft(ml_pmp.dll)",
- init,
- quit,
- PluginMessageProc,
- 0,
- 0,
- 0,
- };
- C_ItemList devices;
- C_ItemList loadingDevices;
- extern HNAVITEM cloudQueueTreeItem;
- static HNAVITEM navigationRoot = NULL;
- static ATOM viewAtom = 0;
- int groupBtn = 1, customAllowed = 0, enqueuedef = 0;
- extern HWND hwndMediaView;
- extern DeviceView * currentViewedDevice;
- HMENU m_context_menus = NULL, m_context_menus2 = NULL;
- int prefsPageLoaded = 0, profile = 0;
- prefsDlgRecW prefsPage;
- prefsDlgRecW pluginsPrefsPage;
- C_Config * global_config;
- C_Config * gen_mlconfig;
- UINT genhotkeys_add_ipc;
- HANDLE hMainThread;
- UINT_PTR mainTreeHandle;
- extern HINSTANCE cloud_hinst;
- extern int IPC_GET_CLOUD_HINST, IPC_LIBRARY_PLAYLISTS_REFRESH;
- void deviceConnected(Device * dev);
- void deviceDisconnected(Device * dev);
- void deviceLoading(pmpDeviceLoading * load);
- void deviceNameChanged(Device * dev);
- //extern CRITICAL_SECTION listTransfersLock;
- CRITICAL_SECTION csenumdrives;
- api_playlists *AGAVE_API_PLAYLISTS = 0;
- api_playlistmanager *AGAVE_API_PLAYLISTMANAGER = 0;
- api_mldb *AGAVE_API_MLDB = 0;
- api_memmgr *WASABI_API_MEMMGR = 0;
- api_syscb *WASABI_API_SYSCB = 0;
- api_application *WASABI_API_APP = 0;
- api_podcasts *AGAVE_API_PODCASTS = 0;
- api_albumart *AGAVE_API_ALBUMART = 0;
- api_stats *AGAVE_API_STATS = 0;
- api_threadpool *WASABI_API_THREADPOOL = 0;
- api_devicemanager *AGAVE_API_DEVICEMANAGER = 0;
- api_metadata *AGAVE_API_METADATA = 0;
- // wasabi based services for localisation support
- api_language *WASABI_API_LNG = 0;
- HINSTANCE WASABI_API_LNG_HINST = 0;
- HINSTANCE WASABI_API_ORIG_HINST = 0;
- static const GUID pngLoaderGUID =
- { 0x5e04fb28, 0x53f5, 0x4032, { 0xbd, 0x29, 0x3, 0x2b, 0x87, 0xec, 0x37, 0x25 } };
- static svc_imageLoader *wasabiPngLoader = NULL;
- HWND mainMessageWindow = 0;
- static bool classRegistered=0;
- HWND CreateDummyWindow()
- {
- if (!classRegistered)
- {
- WNDCLASSW wc = {0, };
- wc.style = 0;
- wc.lpfnWndProc = DeviceMsgProc;
- wc.hInstance = plugin.hDllInstance;
- wc.hIcon = 0;
- wc.hCursor = NULL;
- wc.lpszClassName = L"ml_pmp_window";
- if (!RegisterClassW(&wc))
- return 0;
- classRegistered = true;
- }
- HWND dummy = CreateWindowW(L"ml_pmp_window", L"ml_pmp_window", 0, 0, 0, 0, 0, NULL, NULL, plugin.hDllInstance, NULL);
- return dummy;
- }
- genHotkeysAddStruct hksync = { 0, HKF_UNICODE_NAME, WM_USER, 0, 0, "ml_pmp_sync", 0 };
- genHotkeysAddStruct hkautofill = { 0, HKF_UNICODE_NAME, WM_USER + 1, 0, 0, "ml_pmp_autofill", 0 };
- genHotkeysAddStruct hkeject = { 0, HKF_UNICODE_NAME, WM_USER + 2, 0, 0, "ml_pmp_eject", 0 };
- template <class api_T>
- void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
- {
- if (plugin.service)
- {
- waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
- if (factory)
- api_t = reinterpret_cast<api_T *>( factory->getInterface() );
- }
- }
- template <class api_T>
- void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
- {
- if (plugin.service && api_t)
- {
- waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
- if (factory)
- factory->releaseInterface(api_t);
- }
- api_t = NULL;
- }
- HNAVITEM NavigationItem_Find(HNAVITEM root, const wchar_t *name, BOOL allow_root = 0)
- {
- NAVCTRLFINDPARAMS find;
- HNAVITEM item;
- if (NULL == name)
- return NULL;
- if (NULL == plugin.hwndLibraryParent)
- return NULL;
- find.pszName = (wchar_t*)name;
- find.cchLength = -1;
- find.compFlags = NICF_INVARIANT;
- find.fFullNameSearch = FALSE;
- item = MLNavCtrl_FindItemByName(plugin.hwndLibraryParent, &find);
- if (NULL == item)
- return NULL;
- if (!allow_root)
- {
- // if allowed then we can look for root level items which
- // is really for getting 'cloud' devices to another group
- if (NULL != root &&
- root != MLNavItem_GetParent(plugin.hwndLibraryParent, item))
- {
- item = NULL;
- }
- }
- return item;
- }
- HNAVITEM GetNavigationRoot(BOOL forceCreate)
- {
- if (NULL == navigationRoot &&
- FALSE != forceCreate)
- {
- NAVINSERTSTRUCT nis = {0};
- wchar_t buffer[512] = {0};
- WASABI_API_LNGSTRINGW_BUF(IDS_PORTABLES, buffer, ARRAYSIZE(buffer));
- nis.hParent = NULL;
- nis.hInsertAfter = NCI_LAST;
- nis.item.cbSize = sizeof(NAVITEM);
- nis.item.mask = NIMF_TEXT | NIMF_TEXTINVARIANT | NIMF_STYLE | NIMF_ITEMID | NIMF_PARAM;
- nis.item.id = MAINTREEID;
- nis.item.pszInvariant = L"Portables";
- nis.item.style = NIS_HASCHILDREN;
- nis.item.pszText = buffer;
- nis.item.lParam = -1;
- navigationRoot = MLNavCtrl_InsertItem(plugin.hwndLibraryParent, &nis);
- if (NULL != navigationRoot)
- {
- SetTimer(mainMessageWindow, PROGRESSTIMERID, 250, ProgressTimerTickCb);
- }
- }
- return navigationRoot;
- }
- static HNAVITEM GetNavigationItemFromMessage(int msg, INT_PTR param)
- {
- return (msg < ML_MSG_NAVIGATION_FIRST) ?
- MLNavCtrl_FindItemById(plugin.hwndLibraryParent, param) :
- (HNAVITEM)param;
- }
- void Menu_ConvertRatingMenuStar(HMENU menu, UINT menu_id)
- {
- MENUITEMINFOW mi = {sizeof(mi), MIIM_DATA | MIIM_TYPE, MFT_STRING};
- wchar_t rateBuf[32], *rateStr = rateBuf;
- mi.dwTypeData = rateBuf;
- mi.cch = 32;
- if(GetMenuItemInfoW(menu, menu_id, FALSE, &mi))
- {
- while(rateStr && *rateStr)
- {
- if(*rateStr == L'*') *rateStr = L'\u2605';
- rateStr=CharNextW(rateStr);
- }
- SetMenuItemInfoW(menu, menu_id, FALSE, &mi);
- }
- }
- static ServiceWatcher serviceWatcher;
- static int init()
- {
- // if there are no pmp_*.dll then no reason to load
- if (!testForDevPlugins())
- return ML_INIT_FAILURE;
- genrand_int31 = (int (*)())SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GET_RANDFUNC);
- if (0 == viewAtom)
- {
- viewAtom = GlobalAddAtomW(L"WinampPortableMediaView");
- if (0 == viewAtom)
- return 2;
- }
- TranscoderImp::init();
- InitializeCriticalSection(&csenumdrives);
-
- Tataki::Init(plugin.service);
- ServiceBuild( AGAVE_API_PLAYLISTS, api_playlistsGUID );
- ServiceBuild( AGAVE_API_PLAYLISTMANAGER, api_playlistmanagerGUID );
- ServiceBuild( WASABI_API_SYSCB, syscbApiServiceGuid );
- ServiceBuild( WASABI_API_APP, applicationApiServiceGuid );
- ServiceBuild( AGAVE_API_STATS, AnonymousStatsGUID );
- ServiceBuild( WASABI_API_THREADPOOL, ThreadPoolGUID );
- ServiceBuild( AGAVE_API_DEVICEMANAGER, DeviceManagerGUID );
- ServiceBuild( AGAVE_API_ALBUMART, albumArtGUID );
- ServiceBuild( AGAVE_API_METADATA, api_metadataGUID );
- // loader so that we can get the localisation service api for use
- ServiceBuild( WASABI_API_LNG, languageApiGUID );
- ServiceBuild( WASABI_API_MEMMGR, memMgrApiServiceGuid );
- // no guarantee that AGAVE_API_MLDB will be available yet, so we'll start a watcher for it
- serviceWatcher.WatchWith( plugin.service );
- serviceWatcher.WatchFor( &AGAVE_API_MLDB, mldbApiGuid );
- serviceWatcher.WatchFor( &AGAVE_API_PODCASTS, api_podcastsGUID );
- WASABI_API_SYSCB->syscb_registerCallback( &serviceWatcher );
- mediaLibrary.library = plugin.hwndLibraryParent;
- mediaLibrary.winamp = plugin.hwndWinampParent;
- mediaLibrary.instance = plugin.hDllInstance;
- mediaLibrary.GetIniDirectory();
- mediaLibrary.GetIniDirectoryW();
- // need to have this initialised before we try to do anything with localisation features
- WASABI_API_START_LANG(plugin.hDllInstance,MlPMPLangGUID);
-
- static wchar_t szDescription[256];
- StringCbPrintfW(szDescription, ARRAYSIZE(szDescription), WASABI_API_LNGSTRINGW(IDS_NULLSOFT_PMP_SUPPORT), PLUGIN_VERSION);
- plugin.description = (char*)szDescription;
- hMainThread = GetCurrentThread();
- //InitializeCriticalSection(&listTransfersLock);
- global_config = new C_Config( (wchar_t *)mediaLibrary.GetWinampIniW() );
- profile = global_config->ReadInt( L"profile", 0, L"Winamp" );
- gen_mlconfig = new C_Config( (wchar_t *)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETMLINIFILEW ), L"gen_ml_config" );
- m_context_menus = WASABI_API_LOADMENU( IDR_CONTEXTMENUS );
- m_context_menus2 = WASABI_API_LOADMENU( IDR_CONTEXTMENUS );
- HMENU rate_hmenu = GetSubMenu(GetSubMenu(m_context_menus,0),7);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_5);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_4);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_3);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_2);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_1);
- rate_hmenu = GetSubMenu(GetSubMenu(m_context_menus,1),4);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_5);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_4);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_3);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_2);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_1);
- rate_hmenu = GetSubMenu(GetSubMenu(m_context_menus,2),7);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_5);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_4);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_3);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_2);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_1);
- rate_hmenu = GetSubMenu(GetSubMenu(m_context_menus,7),5);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_5);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_4);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_3);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_2);
- Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATE_1);
- //subclass winamp window
- mainMessageWindow = CreateDummyWindow();
- prefsPage.hInst = WASABI_API_LNG_HINST;
- prefsPage.dlgID = IDD_CONFIG_GLOBAL;
- prefsPage.name = _wcsdup( WASABI_API_LNGSTRINGW( IDS_PORTABLES ) );
- prefsPage.where = 6;
- prefsPage.proc = global_config_dlgproc;
- pluginsPrefsPage.hInst = WASABI_API_LNG_HINST;
- pluginsPrefsPage.dlgID = IDD_CONFIG_PLUGINS;
- pluginsPrefsPage.name = prefsPage.name;
- pluginsPrefsPage.where = 1;
- pluginsPrefsPage.proc = config_dlgproc_plugins;
- // only insert the portables page if we've actually loaded a pmp_*.dll
- int count = 0;
- if(loadDevPlugins(&count) && count > 0)
- {
- SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(intptr_t)&pluginsPrefsPage,IPC_ADD_PREFS_DLGW);
- }
- else if (!count)
- {
- // and if there are none, then cleanup and also notify ml_devices.dll to
- // shut-down as no need for it to keep running if there's not going to be
- // anything else running (as unlikely we'd have use for it without ml_pmp
- quit();
- winampMediaLibraryPlugin *(*gp)();
- gp = (winampMediaLibraryPlugin * (__cdecl *)(void))GetProcAddress(GetModuleHandleW(L"ml_devices.dll"), "winampGetMediaLibraryPlugin");
- if (gp)
- {
- winampMediaLibraryPlugin *mlplugin = gp();
- if (mlplugin && (mlplugin->version >= MLHDR_VER_OLD && mlplugin->version <= MLHDR_VER))
- {
- mlplugin->quit();
- }
- }
- return ML_INIT_FAILURE;
- }
- // we've got pmp_*.dll to load, so lets start the fun...
- Devices_Init();
- if (AGAVE_API_DEVICEMANAGER)
- {
- SetTimer(mainMessageWindow, PROGRESSTIMERID, 250, ProgressTimerTickCb);
- }
- else if (!global_config->ReadInt(L"HideRoot",0))
- {
- GetNavigationRoot(TRUE);
- }
- SetTimer(mainMessageWindow,COMMITTIMERID,5000,NULL);
- IPC_LIBRARY_PLAYLISTS_REFRESH = SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"ml_playlist_refresh", IPC_REGISTER_WINAMP_IPCMESSAGE);
- IPC_GET_CLOUD_HINST = (INT)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"WinampCloud", IPC_REGISTER_WINAMP_IPCMESSAGE);
- cloud_hinst = (HINSTANCE)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GET_CLOUD_HINST);
- // set up hotkeys...
- genhotkeys_add_ipc = SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&"GenHotkeysAdd",IPC_REGISTER_WINAMP_IPCMESSAGE);
- hksync.wnd = hkautofill.wnd = hkeject.wnd = mainMessageWindow;
- hksync.name = (char*)_wcsdup(WASABI_API_LNGSTRINGW(IDS_GHK_SYNC_PORTABLE_DEVICE));
- PostMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&hksync,genhotkeys_add_ipc);
- hkautofill.name = (char*)_wcsdup(WASABI_API_LNGSTRINGW(IDS_GHK_AUTOFILL_PORTABLE_DEVICE));
- PostMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&hkautofill,genhotkeys_add_ipc);
- hkeject.name = (char*)_wcsdup(WASABI_API_LNGSTRINGW(IDS_GHK_EJECT_PORTABLE_DEVICE));
- PostMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&hkeject,genhotkeys_add_ipc);
- return ML_INIT_SUCCESS;
- }
- bool quitting=false;
- static void quit()
- {
- // trigger transfer kill
- int i = devices.GetSize();
- if (i > 0)
- {
- while(i-- > 0)
- {
- DeviceView * device = ((DeviceView*)devices.Get(i));
- if (device) device->threadKillswitch = 1;
- }
- }
- quitting = true;
- KillTimer(mainMessageWindow, COMMITTIMERID);
- DeviceMsgProc(NULL, WM_TIMER, COMMITTIMERID, 0);
- i = devices.GetSize();
- if (i > 0)
- {
- while(i-- > 0)
- {
- DeviceView * device = ((DeviceView*)devices.Get(i));
- if (device) device->dev->Close();
- }
- }
- unloadDevPlugins();
- stopServer();
- HWND f = mainMessageWindow;
- mainMessageWindow = 0;
- DestroyWindow(f);
- delete global_config;
- WASABI_API_SYSCB->syscb_deregisterCallback(&serviceWatcher);
- serviceWatcher.Clear();
- ServiceRelease( AGAVE_API_PLAYLISTS, api_playlistsGUID );
- ServiceRelease( AGAVE_API_PLAYLISTMANAGER, api_playlistmanagerGUID );
- ServiceRelease( WASABI_API_SYSCB, syscbApiServiceGuid );
- ServiceRelease( WASABI_API_APP, applicationApiServiceGuid );
- ServiceRelease( WASABI_API_LNG, languageApiGUID );
- ServiceRelease( WASABI_API_MEMMGR, memMgrApiServiceGuid );
- ServiceRelease( AGAVE_API_MLDB, mldbApiGuid );
- ServiceRelease( AGAVE_API_PODCASTS, api_podcastsGUID );
- ServiceRelease( AGAVE_API_STATS, AnonymousStatsGUID );
- ServiceRelease( AGAVE_API_DEVICEMANAGER, DeviceManagerGUID );
- ServiceRelease( AGAVE_API_ALBUMART, albumArtGUID );
- ServiceRelease( AGAVE_API_METADATA, api_metadataGUID );
- if (NULL != wasabiPngLoader)
- {
- ServiceRelease(wasabiPngLoader, pngLoaderGUID);
- wasabiPngLoader = NULL;
- }
- DeleteCriticalSection(&csenumdrives);
- TranscoderImp::quit();
- delete gen_mlconfig;
- Tataki::Quit();
- ServiceRelease(WASABI_API_THREADPOOL, ThreadPoolGUID);
- if (0 != viewAtom)
- {
- GlobalDeleteAtom(viewAtom);
- viewAtom = 0;
- }
- }
- typedef struct { ULONG_PTR param; void * proc; int state; CRITICAL_SECTION lock;} spc ;
- static VOID CALLBACK spc_caller(ULONG_PTR dwParam) {
- spc * s = (spc*)dwParam;
- if(!s) return;
- EnterCriticalSection(&s->lock);
- if(s->state == -1) { LeaveCriticalSection(&s->lock); DeleteCriticalSection(&s->lock); free(s); return; }
- s->state = 2;
- void (CALLBACK *p)(ULONG_PTR dwParam);
- p = (void (CALLBACK *)(ULONG_PTR dwParam))s->proc;
- if(p) p(s->param);
- s->state=1;
- LeaveCriticalSection(&s->lock);
- }
- static int spc_GetState(spc *s)
- {
- EnterCriticalSection(&s->lock);
- int state = s->state;
- LeaveCriticalSection(&s->lock);
- return state;
- }
- // p must be of type void (CALLBACK *)(ULONG_PTR dwParam). Returns 0 for success.
- int SynchronousProcedureCall(void * p, ULONG_PTR dwParam) {
- if(!p) return 1;
- spc * s = (spc*)calloc(1, sizeof(spc));
- InitializeCriticalSection(&s->lock);
- s->param = dwParam;
- s->proc = p;
- s->state = 0;
- #if 1 // _WIN32_WINNT >= 0x0400
- if(!QueueUserAPC(spc_caller,hMainThread,(ULONG_PTR)s)) { DeleteCriticalSection(&s->lock); free(s); return 1; } //failed
- #else
- if(!mainMessageWindow) { DeleteCriticalSection(&s->lock); free(s); return 1; } else PostMessage(mainMessageWindow,WM_USER+3,(WPARAM)spc_caller,(LPARAM)s);
- #endif
- int i=0;
- while (spc_GetState(s) != 1)
- {
- if (SleepEx(10,TRUE) == 0)
- i++;
- if(i >= 100)
- {
- EnterCriticalSection(&s->lock);
- s->state = -1;
- LeaveCriticalSection(&s->lock);
- return 1;
- }
- }
- DeleteCriticalSection(&s->lock);
- free(s);
- return 0;
- }
- static VOID CALLBACK getTranscoder(ULONG_PTR dwParam)
- {
- C_Config * conf = global_config;
- for(int i=0; i<devices.GetSize(); i++)
- {
- DeviceView * d = (DeviceView *)devices.Get(i);
- if(d->dev == *(Device **)dwParam) { conf = d->config; break; }
- }
- Transcoder ** t = (Transcoder**)dwParam;
- *t = new TranscoderImp(plugin.hwndWinampParent,plugin.hDllInstance,conf, *(Device **)dwParam);
- }
- static void CALLBACK ProgressTimerTickCb(HWND hwnd, UINT uMsg, UINT_PTR eventId, unsigned long elapsed)
- {
- wchar_t *buf = (wchar_t*)calloc(sizeof(wchar_t), 256);
- NAVITEM itemInfo = {0};
- HNAVITEM rootItem = GetNavigationRoot(FALSE);
- if (!AGAVE_API_DEVICEMANAGER && NULL == rootItem)
- {
- KillTimer(hwnd, eventId);
- if (buf) free(buf);
- return;
- }
- // TODO need to get this working for a merged instance...
- int num = 0,total = 0, percent = 0;
- for(int i=0; i<devices.GetSize(); i++)
- {
- DeviceView * dev = (DeviceView*)devices.Get(i);
- LinkedQueue * txQueue = getTransferQueue(dev);
- LinkedQueue * finishedTX = getFinishedTransferQueue(dev);
- int txProgress = getTransferProgress(dev);
- int size = (txQueue ? txQueue->GetSize() : 0);
- int device_num = (100 * size) - txProgress;
- num += device_num;
- int device_total = 100 * size + 100 * (finishedTX ? finishedTX->GetSize() : 0);
- total += device_total;
- percent = (0 != device_total) ? (((device_total - device_num) * 100) / device_total) : -1;
- // TODO need to do something to handle it sticking on 100%
- if (dev->queueTreeItem)
- {
- itemInfo.cbSize = sizeof(itemInfo);
- itemInfo.hItem = dev->queueTreeItem;
- itemInfo.mask = NIMF_PARAM;
- if (MLNavItem_GetInfo(plugin.hwndLibraryParent, &itemInfo) && itemInfo.lParam != percent)
- {
- if (-1 == percent)
- WASABI_API_LNGSTRINGW_BUF(IDS_TRANSFERS,buf, 256);
- else
- StringCbPrintfW(buf, 256, WASABI_API_LNGSTRINGW(IDS_TRANSFERS_PERCENT), percent);
- itemInfo.mask |= NIMF_TEXT;
- itemInfo.pszText = buf;
- itemInfo.lParam = percent;
- itemInfo.cchTextMax = -1;
- MLNavItem_SetInfo(plugin.hwndLibraryParent, &itemInfo);
- }
- }
- dev->UpdateActivityState();
- }
- if (!rootItem)
- {
- if (buf) free(buf);
- return;
- }
- percent = (0 != total) ? (((total-num)*100)/total) : -1;
- itemInfo.cbSize = sizeof(itemInfo);
- itemInfo.hItem = rootItem;
- itemInfo.mask = NIMF_PARAM;
- if (FALSE == MLNavItem_GetInfo(plugin.hwndLibraryParent, &itemInfo))
- {
- if (buf) free(buf);
- return;
- }
- if (itemInfo.lParam != percent)
- {
- if (-1 == percent)
- WASABI_API_LNGSTRINGW_BUF(IDS_PORTABLES,buf,256);
- else
- StringCbPrintfW(buf, sizeof(buf), WASABI_API_LNGSTRINGW(IDS_PORTABLES_PERCENT),percent);
-
- itemInfo.mask |= NIMF_TEXT;
- itemInfo.pszText = buf;
- itemInfo.lParam = percent;
- itemInfo.cchTextMax = -1;
- MLNavItem_SetInfo(plugin.hwndLibraryParent, &itemInfo);
- }
- if (buf) free(buf);
- }
- extern LRESULT CALLBACK TranscodeMsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- static void EnumDrives(ENUM_DRIVES_CALLBACK callback)
- {
- DWORD drives=GetLogicalDrives();
- wchar_t drivestr[4] = L"X:\\";
- for(int i=2;i<25;i++) if(drives&(1<<i))
- {
- EnterCriticalSection(&csenumdrives);
- UINT olderrmode=SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
- drivestr[0] = L'A'+i;
- callback(drivestr[0],GetDriveTypeW(drivestr));
- SetErrorMode(olderrmode);
- LeaveCriticalSection(&csenumdrives);
- }
- }
- LRESULT CALLBACK DeviceMsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- if(uMsg == WM_WA_IPC && hwnd != mainMessageWindow) return TranscodeMsgProc(hwnd,uMsg,wParam,lParam);
- switch(uMsg)
- {
- case WM_USER: // hotkey: sync
- if(devices.GetSize() > 0)
- {
- if (!((DeviceView *)devices.Get(0))->isCloudDevice)
- ((DeviceView *)devices.Get(0))->Sync();
- else
- ((DeviceView *)devices.Get(0))->CloudSync();
- }
- break;
- case WM_USER+1: // hotkey: autofill
- if(devices.GetSize() > 0)
- ((DeviceView *)devices.Get(0))->Autofill();
- break;
- case WM_USER+2: // hotkey: eject
- if(devices.GetSize() > 0)
- ((DeviceView *)devices.Get(0))->Eject();
- break;
- case WM_USER+3:
- {
- void (CALLBACK *p)(ULONG_PTR dwParam);
- p = (void (CALLBACK *)(ULONG_PTR dwParam))wParam;
- p((ULONG_PTR)lParam);
- }
- break;
- case WM_USER+4: // refreshes cloud views (re-checks if we've moved away)
- if (IsWindow(hwndMediaView) && currentViewedDevice && currentViewedDevice->isCloudDevice)
- {
- PostMessage(plugin.hwndLibraryParent, WM_USER + 30, 0, 0);
- }
- break;
- case WM_USER+5: // removes cloud devices from a cloud sources logout...
- {
- for (int i = devices.GetSize() - 1; i > -1; --i)
- {
- DeviceView * dev = (DeviceView *)devices.Get(i);
- if (dev->isCloudDevice)
- dev->dev->Close();
- }
- break;
- }
- case WM_PMP_IPC:
- {
- switch(lParam)
- {
- case PMP_IPC_DEVICECONNECTED:
- deviceConnected((Device*)wParam);
- break;
- case PMP_IPC_DEVICEDISCONNECTED:
- deviceDisconnected((Device*)wParam);
- break;
- case PMP_IPC_DEVICELOADING:
- deviceLoading((pmpDeviceLoading *)wParam);
- break;
- case PMP_IPC_DEVICENAMECHANGED:
- deviceNameChanged((Device*)wParam);
- break;
- case PMP_IPC_DEVICECLOUDTRANSFER:
- {
- int ret = 0;
- cloudDeviceTransfer * transfer = (cloudDeviceTransfer *)wParam;
- if (transfer)
- {
- for (int i = 0; i < devices.GetSize(); i++)
- {
- DeviceView * dev = (DeviceView *)devices.Get(i);
- if (dev->dev->extraActions(DEVICE_IS_CLOUD_TX_DEVICE, (intptr_t)transfer->device_token, 0, 0))
- {
- ret = dev->TransferFromML(ML_TYPE_FILENAMESW, (void *)transfer->filenames, 0, 1);
- }
- }
- }
- return ret;
- }
- case PMP_IPC_GETCLOUDTRANSFERS:
- {
- typedef std::vector<wchar_t*> CloudFiles;
- CloudFiles *pending = (CloudFiles *)wParam;
- if (pending)
- {
- cloudTransferQueue.lock();
- // TODO de-dupe incase going to multiple devices...
- for(int i = 0; i < cloudTransferQueue.GetSize(); i++)
- {
- pending->push_back(((CopyInst *)cloudTransferQueue.Get(i))->sourceFile);
- }
- cloudTransferQueue.unlock();
- return pending->size();
- }
- return 0;
- }
- case PMP_IPC_GET_TRANSCODER:
- {
- void * t = (void*)wParam;
- getTranscoder((ULONG_PTR)&t);
- if (t == (void*)wParam) return 0;
- return (LRESULT)t;
- }
- case PMP_IPC_RELEASE_TRANSCODER:
- delete ((TranscoderImp *)wParam);
- break;
- case PMP_IPC_ENUM_ACTIVE_DRIVES:
- {
- if (wParam == 0)
- return (LRESULT)EnumDrives;
- else
- EnumDrives((ENUM_DRIVES_CALLBACK)wParam);
- }
- break;
- case PMP_IPC_GET_INI_FILE:
- for (int i = 0; i < devices.GetSize(); i++)
- {
- DeviceView * dev = (DeviceView *)devices.Get(i);
- if(dev->dev == (Device*)wParam) return (intptr_t)dev->config->GetIniFile();
- }
- break;
- case PMP_IPC_GET_PREFS_VIEW:
- {
- pmpDevicePrefsView *view = (pmpDevicePrefsView *)wParam;
- if (view)
- {
- for (int i = 0; i < devices.GetSize(); i++)
- {
- DeviceView * dev = (DeviceView *)devices.Get(i);
- if (!lstrcmpA(dev->GetName(), view->dev_name))
- {
- return (LRESULT)OnSelChanged(view->parent, view->parent, dev);
- }
- }
- }
- return 0;
- }
- }
- }
- break;
- case WM_DEVICECHANGE:
- {
- int r = wmDeviceChange(wParam,lParam);
- if (r) return r;
- }
- break;
- case WM_TIMER:
- switch(wParam)
- {
- case COMMITTIMERID:
- {
- for(int i=0; i<devices.GetSize(); i++)
- {
- DeviceView * d = (DeviceView *)devices.Get(i);
- LinkedQueue * txQueue = getTransferQueue(d);
- if (txQueue)
- {
- if(d->commitNeeded && !txQueue->GetSize())
- {
- d->commitNeeded = false;
- d->dev->commitChanges();
- }
- }
- }
- }
- break;
- }
- break;
- }
- return DefWindowProc(hwnd, uMsg, wParam, lParam);
- }
- void UpdateLoadingCaption(wchar_t * caption, void * context)
- {
- NAVITEM itemInfo = {0};
- itemInfo.hItem = (HNAVITEM)context;
- if (NULL == itemInfo.hItem)
- return;
- itemInfo.cbSize = sizeof(itemInfo);
- itemInfo.pszText = caption;
- itemInfo.cchTextMax = -1;
- itemInfo.mask = NIMF_TEXT;
- MLNavItem_SetInfo(plugin.hwndLibraryParent, &itemInfo);
- }
- void deviceLoading(pmpDeviceLoading * load)
- {
- if (!AGAVE_API_DEVICEMANAGER)
- {
- wchar_t buffer[256] = {0};
- NAVINSERTSTRUCT nis = {0};
- MLTREEIMAGE devIcon;
- devIcon.resourceId = IDR_DEVICE_ICON;
- devIcon.hinst = plugin.hDllInstance;
- if(load->dev)
- load->dev->extraActions(DEVICE_SET_ICON,(intptr_t)&devIcon,0,0);
- nis.hParent = GetNavigationRoot(TRUE);
- nis.hInsertAfter = NCI_LAST;
- nis.item.cbSize = sizeof(NAVITEM);
- nis.item.mask = NIMF_TEXT | NIMF_TEXTINVARIANT | NIMF_STYLE | NIMF_IMAGE | NIMF_IMAGESEL;
- nis.item.pszText = WASABI_API_LNGSTRINGW_BUF(IDS_LOADING, buffer, ARRAYSIZE(buffer));
- nis.item.pszInvariant = L"device_loading";
- nis.item.style = NIS_ITALIC;
- nis.item.iImage = icon_store.GetResourceIcon(devIcon.hinst, (LPCWSTR)MAKEINTRESOURCE(devIcon.resourceId));
- nis.item.iSelectedImage = nis.item.iImage;
- load->context = MLNavCtrl_InsertItem(plugin.hwndLibraryParent, &nis);
- load->UpdateCaption = UpdateLoadingCaption;
- loadingDevices.Add(load);
- }
- }
- void finishDeviceLoading(Device * dev)
- {
- for(int i=0; i < loadingDevices.GetSize(); i++)
- {
- pmpDeviceLoading * l = (pmpDeviceLoading *)loadingDevices.Get(i);
- if(l->dev == dev) {
- loadingDevices.Del(i);
- HNAVITEM treeItem = (HNAVITEM)l->context;
- MLNavCtrl_DeleteItem(plugin.hwndLibraryParent,treeItem);
- return;
- }
- }
- }
- void deviceConnected(Device * dev)
- {
- if (!AGAVE_API_DEVICEMANAGER)
- GetNavigationRoot(TRUE);
- Device * oldDev = dev;
- finishDeviceLoading(oldDev);
- if(!devices.GetSize()) startServer();
- DeviceView *pmp_device = new DeviceView(dev);
- devices.Add(pmp_device);
- UpdateDevicesListView(false);
- }
- void deviceDisconnected(Device * dev)
- {
- finishDeviceLoading(dev);
- int cloud_count = 0;
- for(int i = 0; i < devices.GetSize(); i++)
- {
- DeviceView * d = (DeviceView *)devices.Get(i);
- if(d->dev == dev)
- {
- d->threadKillswitch = 1;
- d->transferContext.WaitForKill();
- devices.Del(i);
- d->Unregister();
- d->Release();
- }
- else
- {
- // to keep the 'cloud library' node on the correct expanded state
- // we need to adjust the cloud sources count due to 'all sources'
- if (_strnicmp(d->GetName(), "all_sources", 11) && d->isCloudDevice)
- {
- cloud_count += 1;
- }
- }
- }
- // if we're only showing a single device, then we can just disable everything else
- if (cloud_count == 0)
- {
- HNAVITEM cloud_transfers = NavigationItem_Find(0, L"cloud_transfers", TRUE);
- if (cloud_transfers != NULL)
- {
- MLNavCtrl_DeleteItem(plugin.hwndLibraryParent, cloud_transfers);
- cloudQueueTreeItem = NULL;
- }
- cloud_transfers = NavigationItem_Find(0, L"cloud_add_sources", TRUE);
- if (cloud_transfers != NULL)
- {
- MLNavCtrl_DeleteItem(plugin.hwndLibraryParent, cloud_transfers);
- }
- cloud_transfers = NavigationItem_Find(0, L"cloud_byos", TRUE);
- if (cloud_transfers != NULL)
- {
- MLNavCtrl_DeleteItem(plugin.hwndLibraryParent, cloud_transfers);
- }
- HNAVITEM cloud = NavigationItem_Find(0, L"cloud_sources", TRUE);
- if (cloud != NULL)
- {
- NAVITEM item = {0};
- item.cbSize = sizeof(NAVITEM);
- item.mask = NIMF_IMAGE | NIMF_IMAGESEL;
- item.hItem = cloud;
- item.iImage = item.iSelectedImage = mediaLibrary.AddTreeImageBmp(IDB_TREEITEM_CLOUD);
- MLNavItem_SetInfo(plugin.hwndLibraryParent, &item);
- }
- }
- UpdateDevicesListView(false);
- if(!devices.GetSize() && !loadingDevices.GetSize() && global_config->ReadInt(L"HideRoot",0))
- {
- HNAVITEM rootItem = GetNavigationRoot(FALSE);
- if (NULL != rootItem)
- MLNavCtrl_DeleteItem(plugin.hwndLibraryParent, rootItem);
- }
- if(!devices.GetSize()) stopServer();
- }
- void deviceNameChanged(Device * dev)
- {
- finishDeviceLoading(dev);
- for(int i=0; i < devices.GetSize(); i++)
- {
- DeviceView * d = (DeviceView *)devices.Get(i);
- if(d->dev == dev)
- {
- wchar_t *buffer = (wchar_t*)calloc(sizeof(wchar_t),128);
- if (buffer)
- {
- dev->getPlaylistName(0, buffer, 128);
- UpdateLoadingCaption(buffer, d->treeItem);
- d->SetDisplayName(buffer, 1);
- free(buffer);
- }
- break;
- }
- }
- }
- svc_imageLoader *GetPngLoaderService()
- {
- if (NULL == wasabiPngLoader)
- {
- if (NULL == WASABI_API_MEMMGR)
- return NULL;
- ServiceBuild(wasabiPngLoader, pngLoaderGUID);
- }
- return wasabiPngLoader;
- }
- BOOL FormatResProtocol(const wchar_t *resourceName, const wchar_t *resourceType, wchar_t *buffer, size_t bufferMax)
- {
- unsigned long filenameLength;
- if (NULL == resourceName)
- return FALSE;
- if (FAILED(StringCchCopyExW(buffer, bufferMax, L"res://", &buffer, &bufferMax, 0)))
- return FALSE;
- filenameLength = GetModuleFileNameW(plugin.hDllInstance, buffer, bufferMax);
- if (0 == filenameLength || bufferMax == filenameLength)
- return FALSE;
- buffer += filenameLength;
- bufferMax -= filenameLength;
- if (NULL != resourceType)
- {
- if (FALSE != IS_INTRESOURCE(resourceType))
- {
- if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/#%d", (int)(INT_PTR)resourceType)))
- return FALSE;
- }
- else
- {
- if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/%s", resourceType)))
- return FALSE;
- }
- }
- if (FALSE != IS_INTRESOURCE(resourceName))
- {
- if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/#%d", (int)(INT_PTR)resourceName)))
- return FALSE;
- }
- else
- {
- if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/%s", resourceName)))
- return FALSE;
- }
- return TRUE;
- }
- BOOL
- CenterWindow(HWND window, HWND centerWindow)
- {
- RECT centerRect, windowRect;
- long x, y;
- if (NULL == window ||
- FALSE == GetWindowRect(window, &windowRect))
- {
- return FALSE;
- }
- if (CENTER_OVER_ML_VIEW == centerWindow)
- {
- centerWindow = (HWND)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_GETCURRENTVIEW, 0);
- if (NULL == centerWindow || FALSE == IsWindowVisible(centerWindow))
- centerWindow = CENTER_OVER_ML;
- }
- if (CENTER_OVER_ML == centerWindow)
- {
- centerWindow = plugin.hwndLibraryParent;
- if (NULL == centerWindow || FALSE == IsWindowVisible(centerWindow))
- centerWindow = CENTER_OVER_WINAMP;
- }
-
- if (CENTER_OVER_WINAMP == centerWindow)
- {
- centerWindow = (HWND)SENDWAIPC(plugin.hwndWinampParent, IPC_GETDIALOGBOXPARENT, 0);
- if (FALSE == IsChild(centerWindow, plugin.hwndLibraryParent))
- centerWindow = NULL;
- }
-
- if (NULL == centerWindow ||
- FALSE == IsWindowVisible(centerWindow) ||
- FALSE == GetWindowRect(centerWindow, ¢erRect))
- {
- HMONITOR monitor;
- MONITORINFO monitorInfo;
- monitor = MonitorFromWindow(plugin.hwndWinampParent, MONITOR_DEFAULTTONEAREST);
-
- monitorInfo.cbSize = sizeof(monitorInfo);
- if (NULL == monitor ||
- FALSE == GetMonitorInfo(monitor, &monitorInfo) ||
- FALSE == CopyRect(¢erRect, &monitorInfo.rcWork))
- {
- CopyRect(¢erRect, &windowRect);
- }
- }
- x = centerRect.left + ((centerRect.right - centerRect.left)- (windowRect.right - windowRect.left))/2;
- y = centerRect.top + ((centerRect.bottom - centerRect.top)- (windowRect.bottom - windowRect.top))/2;
- if (x == windowRect.left && y == windowRect.top)
- return FALSE;
- return SetWindowPos(window, NULL, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
- }
- ATOM
- GetViewAtom()
- {
- return viewAtom;
- }
- void *
- GetViewData(HWND hwnd)
- {
- return GetPropW(hwnd, (const wchar_t*)MAKEINTATOM(viewAtom));
- }
- BOOL
- SetViewData(HWND hwnd, void *data)
- {
- return SetPropW(hwnd, (const wchar_t*)MAKEINTATOM(viewAtom), data);
- }
- void *
- RemoveViewData(HWND hwnd)
- {
- return RemovePropW(hwnd, (const wchar_t*)MAKEINTATOM(viewAtom));
- }
- static void URL_GetParameter(const wchar_t *param_start, char *dest, size_t dest_len)
- {
- if (!param_start)
- {
- dest[0]=0;
- return;
- }
- while (param_start && *param_start++ != '=');
- while (param_start && *param_start && dest_len > 1 && *param_start != L'&')
- {
- if (*param_start == '+')
- {
- param_start++;
- *dest++=' ';
- }
- else if (*param_start == L'%' && param_start[1] != L'%' && param_start[1])
- {
- int a=0;
- int b=0;
- for ( b = 0; b < 2; b ++)
- {
- int r=param_start[1+b];
- if (r>='0'&&r<='9') r-='0';
- else if (r>='a'&&r<='z') r-='a'-10;
- else if (r>='A'&&r<='Z') r-='A'-10;
- else break;
- a*=16;
- a+=r;
- }
- if (b < 2)
- {
- *dest++=(char)*param_start++;
- }
- else
- {
- *dest++=a;
- param_start += 3;}
- }
- else
- {
- *dest++=(char)*param_start++;
- }
- dest_len--;
- }
- *dest = 0;
- }
- // this only works for one-character parameters
- static const wchar_t *GetParameterStart(const wchar_t *url, wchar_t param)
- {
- wchar_t lookup[4] = { L'&', param, L'=', 0 };
- lookup[1] = param;
- const wchar_t *val = wcsstr(url, lookup);
- if (!val)
- {
- lookup[0] = L'?';
- val = wcsstr(url, lookup);
- }
- return val;
- }
- extern int serverPort;
- static INT_PTR PluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3)
- {
- int i;
- if (message_type == ML_IPC_HOOKEXTINFOW)
- {
- extendedFileInfoStructW *hookMetadata = (extendedFileInfoStructW *)param1;
- if (hookMetadata->filename && !wcsncmp(hookMetadata->filename, L"http://127.0.0.1:", 17) && _wtoi(hookMetadata->filename + 17) == serverPort)
- {
- if (!_wcsicmp(hookMetadata->metadata, L"artist"))
- {
- char metadata[1024] = {0};
- URL_GetParameter(GetParameterStart(hookMetadata->filename, 'a'), metadata, 1024);
- MultiByteToWideCharSZ(CP_UTF8, 0, metadata, -1, hookMetadata->ret, hookMetadata->retlen);
- return 1;
- }
- else if (!_wcsicmp(hookMetadata->metadata, L"album"))
- {
- char metadata[1024] = {0};
- URL_GetParameter(GetParameterStart(hookMetadata->filename, 'l'), metadata, 1024);
- MultiByteToWideCharSZ(CP_UTF8, 0, metadata, -1, hookMetadata->ret, hookMetadata->retlen);
- return 1;
- }
- else if (!_wcsicmp(hookMetadata->metadata, L"title"))
- {
- char metadata[1024] = {0};
- URL_GetParameter(GetParameterStart(hookMetadata->filename, 't'), metadata, 1024);
- MultiByteToWideCharSZ(CP_UTF8, 0, metadata, -1, hookMetadata->ret, hookMetadata->retlen);
- return 1;
- }
- }
- }
- for(i=0; i < devices.GetSize(); i++)
- {
- DeviceView *deviceView;
- deviceView = (DeviceView *)devices.Get(i);
- if (NULL != deviceView)
- {
- INT_PTR a= deviceView->MessageProc(message_type,param1,param2,param3);
- if(0 != a)
- return a;
- }
- }
-
- if (message_type >= ML_MSG_TREE_BEGIN &&
- message_type <= ML_MSG_TREE_END)
- {
- HNAVITEM item, rootItem;
- item = GetNavigationItemFromMessage(message_type, param1);
- rootItem = GetNavigationRoot(FALSE);
-
- if(message_type == ML_MSG_TREE_ONCREATEVIEW)
- {
- for(i=0; i < loadingDevices.GetSize(); i++)
- {
- pmpDeviceLoading * l = (pmpDeviceLoading *)loadingDevices.Get(i);
- if(NULL != l->context)
- {
- if (((HNAVITEM)l->context) == item)
- {
- HNAVITEM parentItem;
- parentItem = MLNavItem_GetParent(plugin.hwndLibraryParent, item);
- if (NULL == parentItem)
- parentItem = rootItem;
- PostMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)parentItem, ML_IPC_NAVITEM_SELECT);
- return 0;
- }
- }
- }
- }
- if(NULL != item && item == rootItem)
- {
- switch (message_type)
- {
- case ML_MSG_TREE_ONCREATEVIEW:
- return (INT_PTR)WASABI_API_CREATEDIALOGW(IDD_VIEW_PMP_DEVICES,(HWND)param2,pmp_devices_dlgproc);
- case ML_MSG_TREE_ONCLICK:
- switch(param2)
- {
- case ML_ACTION_RCLICK:
- {
- HMENU menu = GetSubMenu(m_context_menus,6);
- int hideRoot = global_config->ReadInt(L"HideRoot",0);
- CheckMenuItem(menu,ID_MAINTREEROOT_AUTOHIDEROOT,hideRoot?MF_CHECKED:MF_UNCHECKED);
- POINT p;
- GetCursorPos(&p);
- int r = Menu_TrackSkinnedPopup(menu,TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY,p.x,p.y,plugin.hwndLibraryParent,NULL);
- switch(r)
- {
- case ID_MAINTREEROOT_AUTOHIDEROOT:
- hideRoot = hideRoot?0:1;
- global_config->WriteInt(L"HideRoot",hideRoot);
- if(hideRoot && devices.GetSize() == 0)
- {
- MLNavCtrl_DeleteItem(plugin.hwndLibraryParent, rootItem);
- }
- break;
- case ID_MAINTREEROOT_PREFERENCES:
- SENDWAIPC(plugin.hwndWinampParent, IPC_OPENPREFSTOPAGE, &pluginsPrefsPage);
- break;
- case ID_MAINTREEROOT_HELP:
- SENDWAIPC(plugin.hwndWinampParent, IPC_OPEN_URL, L"https://help.winamp.com/hc/articles/8106455294612-Winamp-Portables-Guide");
- break;
- }
- }
- break;
- case ML_ACTION_DBLCLICK:
- break;
- case ML_ACTION_ENTER:
- break;
- }
- break;
- case ML_MSG_TREE_ONDROPTARGET:
- break;
- case ML_MSG_TREE_ONDRAG:
- break;
- case ML_MSG_TREE_ONDROP:
- break;
- case ML_MSG_NAVIGATION_ONDELETE:
- navigationRoot = NULL;
- KillTimer(mainMessageWindow, PROGRESSTIMERID);
- return TRUE;
- }
- }
- }
- else if (message_type == ML_MSG_NO_CONFIG)
- {
- if(prefsPage._id == 0)
- return TRUE;
- }
- else if (message_type == ML_MSG_CONFIG)
- {
- if(prefsPage._id == 0) return 0;
- SendMessage(plugin.hwndWinampParent, WM_WA_IPC, prefsPage._id, IPC_OPENPREFSTOPAGE);
- }
- else if (message_type == ML_MSG_NOTOKTOQUIT)
- {
- // see if we have any transfers in progress and if so then prompt on what to do...
- bool transfers = false;
- for (int i = 0; i < devices.GetSize(); i++)
- {
- DeviceView * d = (DeviceView *)devices.Get(i);
- LinkedQueue * txQueue = getTransferQueue(d);
- if(txQueue && txQueue->GetSize() > 0)
- {
- transfers = true;
- break;
- }
- }
- if (transfers)
- {
- wchar_t titleStr[32] = {0};
- if (MessageBoxW(plugin.hwndLibraryParent, WASABI_API_LNGSTRINGW(IDS_CANCEL_TRANSFERS_AND_QUIT),
- WASABI_API_LNGSTRINGW_BUF(IDS_CONFIRM_QUIT,titleStr,32), MB_YESNO | MB_ICONQUESTION) == IDNO)
- return TRUE;
- }
- return FALSE;
- }
- else if(message_type == ML_MSG_ONSENDTOBUILD)
- {
- if (param1 == ML_TYPE_ITEMRECORDLIST || param1 == ML_TYPE_ITEMRECORDLISTW ||
- param1 == ML_TYPE_FILENAMES || param1 == ML_TYPE_FILENAMESW ||
- param1 == ML_TYPE_PLAYLISTS || param1 == ML_TYPE_PLAYLIST)
- {
- if (gen_mlconfig->ReadInt(L"pmp_send_to", DEFAULT_PMP_SEND_TO))
- {
- for(int m = 0, mode = 0; m < 2; m++, mode++)
- {
- int added = 0;
- for(i = 0; i < devices.GetSize(); i++)
- {
- DeviceView *deviceView;
- deviceView = (DeviceView *)devices.Get(i);
- if (NULL != deviceView)
- {
- if (deviceView->dev->extraActions(DEVICE_SENDTO_UNSUPPORTED, 0, 0, 0) == 0)
- {
- wchar_t buffer[128] = {0};
- deviceView->dev->getPlaylistName(0, buffer, 128);
- if (buffer[0])
- {
- // TODO - this is to block true playlists from appearing on the sendto
- // for cloud playlists handling - remove this when we can do more
- // than just uploading the playlist blob without the actual files
- if (deviceView->isCloudDevice && param3 == ML_TYPE_PLAYLIST) continue;
- if (!deviceView->isCloudDevice == mode)
- {
- if (!added)
- {
- mediaLibrary.BranchSendTo(param2);
- added = 1;
- }
- mediaLibrary.AddToBranchSendTo(buffer, param2, reinterpret_cast<INT_PTR>(deviceView));
- }
- }
- }
- }
- }
- if (added)
- {
- mediaLibrary.EndBranchSendTo(WASABI_API_LNGSTRINGW((!m ? IDS_SENDTO_CLOUD : IDS_SENDTO_DEVICES)), param2);
- }
- }
- }
- }
- }
- else if (message_type == ML_MSG_VIEW_PLAY_ENQUEUE_CHANGE)
- {
- enqueuedef = param1;
- groupBtn = param2;
- if (IsWindow(hwndMediaView))
- PostMessage(hwndMediaView, WM_APP + 104, param1, param2);
- return 0;
- }
- return 0;
- }
- extern "C" {
- __declspec( dllexport ) winampMediaLibraryPlugin * winampGetMediaLibraryPlugin()
- {
- return &plugin;
- }
- __declspec( dllexport ) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) {
- // cleanup the ml tree so the portables root isn't left
- HNAVITEM rootItem = GetNavigationRoot(FALSE);
- if(NULL != rootItem)
- MLNavCtrl_DeleteItem(plugin.hwndLibraryParent, rootItem);
-
- // prompt to remove our settings with default as no (just incase)
- wchar_t title[256] = {0};
- StringCbPrintfW(title, ARRAYSIZE(title), WASABI_API_LNGSTRINGW(IDS_NULLSOFT_PMP_SUPPORT), PLUGIN_VERSION);
- if(MessageBoxW(hwndDlg,WASABI_API_LNGSTRINGW(IDS_DO_YOU_ALSO_WANT_TO_REMOVE_SETTINGS),
- title,MB_YESNO|MB_DEFBUTTON2) == IDYES)
- {
- global_config->WriteString(0,0);
- }
- SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(intptr_t)&pluginsPrefsPage,IPC_REMOVE_PREFS_DLG);
- // allow an on-the-fly removal (since we've got to be with a compatible client build)
- return ML_PLUGIN_UNINSTALL_NOW;
- }
- };
|