1
0

Main.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. #define PLUGIN_VERSION L"3.36"
  2. #include "main.h"
  3. #include "resource.h"
  4. #include "api__ml_local.h"
  5. #include "..\..\General\gen_ml/config.h"
  6. #include <commctrl.h>
  7. #include ".\ml_local.h"
  8. #include "..\..\General\gen_ml/ml_ipc_0313.h"
  9. #include "../replicant/nu/AutoChar.h"
  10. #include <api/service/waServiceFactory.h>
  11. #include "../playlist/api_playlistmanager.h"
  12. #include "mldbApiFactory.h"
  13. #include "../nu/ServiceWatcher.h"
  14. #include "LocalMediaCOM.h"
  15. #include <tataki/export.h>
  16. #include <strsafe.h>
  17. #if 0
  18. // disabled since not building cloud dlls
  19. #include "../ml_cloud/CloudCallback.h"
  20. #endif
  21. static ServiceWatcher serviceWatcher;
  22. static LocalMediaCOM localMediaCOM;
  23. MLDBAPIFactory mldbApiFactory;
  24. mlAddTreeItemStruct newTree;
  25. #if 0
  26. // disabled since not building cloud dlls
  27. static class CloudCallbacks : public CloudCallback
  28. {
  29. void OnCloudUploadStart(const wchar_t *filename) {
  30. SendMessage(m_curview_hwnd, WM_APP + 5, 0, (LPARAM)filename);
  31. }
  32. void OnCloudUploadDone(const wchar_t *filename, int code) {
  33. SendMessage(m_curview_hwnd, WM_APP + 5, MAKEWPARAM(code, 1), (LPARAM)filename);
  34. }
  35. } cloudCallback;
  36. #endif
  37. LRESULT ML_IPC_MENUFUCKER_BUILD = -1, ML_IPC_MENUFUCKER_RESULT = -1;
  38. int IPC_CLOUD_ENABLED = -1;
  39. int CreateView(int treeItem, HWND parent);
  40. static int Init();
  41. static void Quit();
  42. static INT_PTR MessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3);
  43. void SaveAll();
  44. prefsDlgRecW preferences;
  45. static wchar_t preferencesName[64] = {0};
  46. int winampVersion = 0;
  47. int substantives = 0;
  48. int play_enq_rnd_alt = 0;
  49. // Delay load library control << begin >>
  50. #include <delayimp.h>
  51. #pragma comment(lib, "delayimp")
  52. bool nde_error = false;
  53. FARPROC WINAPI FailHook(unsigned dliNotify, DelayLoadInfo *dli)
  54. {
  55. nde_error = true;
  56. return 0;
  57. }
  58. /*
  59. extern "C"
  60. {
  61. PfnDliHook __pfnDliFailureHook2 = FailHook;
  62. }
  63. // Delay load library control << end >>
  64. */
  65. #define CBCLASS PLCallBackW
  66. START_DISPATCH;
  67. VCB(IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile)
  68. END_DISPATCH;
  69. #undef CBCLASS
  70. template <class api_T>
  71. void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
  72. {
  73. if (plugin.service)
  74. {
  75. waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
  76. if (factory)
  77. api_t = reinterpret_cast<api_T *>( factory->getInterface() );
  78. }
  79. }
  80. template <class api_T>
  81. void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
  82. {
  83. if (plugin.service && api_t)
  84. {
  85. waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
  86. if (factory)
  87. factory->releaseInterface(api_t);
  88. }
  89. api_t = NULL;
  90. }
  91. extern WORD waMenuID;
  92. DEFINE_EXTERNAL_SERVICE(api_application, WASABI_API_APP);
  93. DEFINE_EXTERNAL_SERVICE(api_explorerfindfile, WASABI_API_EXPLORERFINDFILE);
  94. DEFINE_EXTERNAL_SERVICE(api_language, WASABI_API_LNG);
  95. DEFINE_EXTERNAL_SERVICE(api_syscb, WASABI_API_SYSCB);
  96. DEFINE_EXTERNAL_SERVICE(api_memmgr, WASABI_API_MEMMGR);
  97. DEFINE_EXTERNAL_SERVICE(api_albumart, AGAVE_API_ALBUMART);
  98. DEFINE_EXTERNAL_SERVICE(api_metadata, AGAVE_API_METADATA);
  99. DEFINE_EXTERNAL_SERVICE(api_playlistmanager, AGAVE_API_PLAYLISTMANAGER);
  100. DEFINE_EXTERNAL_SERVICE(api_itunes_importer, AGAVE_API_ITUNES_IMPORTER);
  101. DEFINE_EXTERNAL_SERVICE(api_playlist_generator, AGAVE_API_PLAYLIST_GENERATOR);
  102. DEFINE_EXTERNAL_SERVICE(api_threadpool, WASABI_API_THREADPOOL);
  103. HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
  104. int sse_flag;
  105. int Init()
  106. {
  107. #ifdef _M_IX86
  108. int flags_edx;
  109. _asm
  110. {
  111. mov eax, 1
  112. cpuid
  113. mov flags_edx, edx
  114. }
  115. sse_flag = flags_edx & 0x02000000;
  116. #else
  117. sse_flag=1; // always supported on amd64
  118. #endif
  119. InitializeCriticalSection(&g_db_cs);
  120. waMenuID = (WORD)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_REGISTER_LOWORD_COMMAND);
  121. Tataki::Init(plugin.service);
  122. plugin.service->service_register(&mldbApiFactory);
  123. ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
  124. ServiceBuild(WASABI_API_LNG, languageApiGUID);
  125. ServiceBuild(WASABI_API_EXPLORERFINDFILE, ExplorerFindFileApiGUID);
  126. ServiceBuild(AGAVE_API_ALBUMART, albumArtGUID);
  127. ServiceBuild(AGAVE_API_METADATA, api_metadataGUID);
  128. ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
  129. ServiceBuild(WASABI_API_SYSCB, syscbApiServiceGuid);
  130. ServiceBuild(AGAVE_API_PLAYLISTMANAGER, api_playlistmanagerGUID);
  131. ServiceBuild(WASABI_API_THREADPOOL, ThreadPoolGUID);
  132. //ServiceBuild(AGAVE_API_PLAYLIST_GENERATOR, api_playlist_generator::getServiceGuid());
  133. serviceWatcher.WatchWith(plugin.service);
  134. serviceWatcher.WatchFor(&AGAVE_API_ITUNES_IMPORTER, api_itunes_importer::getServiceGuid());
  135. serviceWatcher.WatchFor(&AGAVE_API_PLAYLIST_GENERATOR, api_playlist_generator::getServiceGuid());
  136. WASABI_API_SYSCB->syscb_registerCallback(&serviceWatcher);
  137. #if 0
  138. // disabled since not building cloud dlls
  139. WASABI_API_SYSCB->syscb_registerCallback(&cloudCallback);
  140. #endif
  141. // need to have this initialised before we try to do anything with localisation features
  142. WASABI_API_START_LANG(plugin.hDllInstance,MlLocalLangGUID);
  143. wchar_t buf[2] = {0};
  144. if(LoadString(WASABI_API_LNG_HINST,IDS_SUBSTANTIVES,buf,2)){
  145. substantives = 1;
  146. }
  147. // this is used to load alternative play/enqueue random strings where
  148. // the default implementation will cause pluralisation issue eg de-de
  149. buf[0] = 0;
  150. if(LoadString(WASABI_API_LNG_HINST,IDS_PLAY_ENQ_RND_ALTERNATIVE,buf,2)){
  151. play_enq_rnd_alt = 1;
  152. }
  153. static wchar_t szDescription[256];
  154. StringCchPrintfW(szDescription, ARRAYSIZE(szDescription),
  155. WASABI_API_LNGSTRINGW(IDS_NULLSOFT_LOCAL_MEDIA), PLUGIN_VERSION);
  156. plugin.description = (char*)szDescription;
  157. ML_IPC_MENUFUCKER_BUILD = (int)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"menufucker_build", IPC_REGISTER_WINAMP_IPCMESSAGE);
  158. ML_IPC_MENUFUCKER_RESULT = (int)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"menufucker_result", IPC_REGISTER_WINAMP_IPCMESSAGE);
  159. IPC_CLOUD_ENABLED = SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"WinampCloudEnabled", IPC_REGISTER_WINAMP_IPCMESSAGE);
  160. mediaLibrary.library = plugin.hwndLibraryParent;
  161. mediaLibrary.winamp = plugin.hwndWinampParent;
  162. mediaLibrary.instance = plugin.hDllInstance;
  163. winampVersion = mediaLibrary.GetWinampVersion();
  164. mediaLibrary.AddDispatch(L"LocalMedia", &localMediaCOM);
  165. // this may look unused, but we want to get this here since mediaLibrary will cache the inidir
  166. // and then we don't run into weird multithreaded SendMessage issues
  167. mediaLibrary.GetIniDirectory();
  168. mediaLibrary.GetIniDirectoryW();
  169. preferences.hInst = WASABI_API_LNG_HINST;
  170. preferences.dlgID = IDD_PREFSFR;
  171. preferences.proc = (void *)PrefsProc;
  172. preferences.name = WASABI_API_LNGSTRINGW_BUF(IDS_LOCAL_MEDIA,preferencesName,64);
  173. preferences.where = 6; // 0;
  174. mediaLibrary.AddPreferences(preferences);
  175. mediaLibrary.AddTreeImage(IDB_TREEITEM_AUDIO, TREE_IMAGE_LOCAL_AUDIO, (BMPFILTERPROC)FILTER_DEFAULT1);
  176. mediaLibrary.AddTreeImage(IDB_TREEITEM_MOSTPLAYED, TREE_IMAGE_LOCAL_MOSTPLAYED, (BMPFILTERPROC)FILTER_DEFAULT1);
  177. mediaLibrary.AddTreeImage(IDB_TREEITEM_NEVERPLAYED, TREE_IMAGE_LOCAL_NEVERPLAYED, (BMPFILTERPROC)FILTER_DEFAULT1);
  178. mediaLibrary.AddTreeImage(IDB_TREEITEM_RECENTLYPLAYED, TREE_IMAGE_LOCAL_RECENTLYPLAYED, (BMPFILTERPROC)FILTER_DEFAULT1);
  179. mediaLibrary.AddTreeImage(IDB_TREEITEM_RECENTLYADDED, TREE_IMAGE_LOCAL_RECENTLYADDED, (BMPFILTERPROC)FILTER_DEFAULT1);
  180. mediaLibrary.AddTreeImage(IDB_TREEITEM_TOPRATED, TREE_IMAGE_LOCAL_TOPRATED, (BMPFILTERPROC)FILTER_DEFAULT1);
  181. mediaLibrary.AddTreeImage(IDB_TREEITEM_VIDEO, TREE_IMAGE_LOCAL_VIDEO, (BMPFILTERPROC)FILTER_DEFAULT1);
  182. mediaLibrary.AddTreeImage(IDB_TREEITEM_PODCASTS, TREE_IMAGE_LOCAL_PODCASTS, (BMPFILTERPROC)FILTER_DEFAULT1);
  183. mediaLibrary.AddTreeImage(IDB_TREEITEM_RECENTLYMODIFIED, TREE_IMAGE_LOCAL_RECENTLYMODIFIED, (BMPFILTERPROC)FILTER_DEFAULT1);
  184. int ret = init();
  185. if (ret) return ret;
  186. NAVINSERTSTRUCT nis = {0};
  187. nis.item.cbSize = sizeof(NAVITEM);
  188. nis.item.pszText = WASABI_API_LNGSTRINGW(IDS_LOCAL_MEDIA);
  189. nis.item.pszInvariant = L"Local Media";
  190. nis.item.style = NIS_HASCHILDREN;
  191. nis.item.id = 1000; // benski> use the old ID for backwards compatability
  192. nis.item.mask = NIMF_TEXT | NIMF_TEXTINVARIANT | NIMF_STYLE | NIMF_ITEMID;
  193. // map to item id (will probably have to change but is a quick port to support invariant item naming)
  194. NAVITEM nvItem = {sizeof(NAVITEM),0,NIMF_ITEMID,};
  195. nvItem.hItem = MLNavCtrl_InsertItem(plugin.hwndLibraryParent, &nis);
  196. MLNavItem_GetInfo(plugin.hwndLibraryParent, &nvItem);
  197. m_query_tree = nvItem.id;
  198. loadQueryTree();
  199. m_query_mode = 0;
  200. m_query_metafile = L"default.vmd";
  201. return ret;
  202. }
  203. void Quit()
  204. {
  205. serviceWatcher.StopWatching();
  206. serviceWatcher.Clear();
  207. // deregister this first, otherwise people might try to use it after we shut down the database!
  208. plugin.service->service_deregister(&mldbApiFactory);
  209. UnhookPlaylistEditor();
  210. Scan_Kill();
  211. closeDb();
  212. delete(g_view_metaconf);
  213. g_view_metaconf = 0;
  214. delete g_config;
  215. g_config = NULL;
  216. KillArtThread();
  217. for (QueryList::iterator i = m_query_list.begin();i != m_query_list.end();i++)
  218. {
  219. queryItem *item = i->second;
  220. if (item)
  221. {
  222. free(item->metafn);
  223. free(item->name);
  224. free(item->query);
  225. }
  226. free(item);
  227. }
  228. m_query_list.clear();
  229. DeleteCriticalSection(&g_db_cs);
  230. ServiceRelease(WASABI_API_APP, applicationApiServiceGuid);
  231. ServiceRelease(WASABI_API_LNG, languageApiGUID);
  232. ServiceRelease(AGAVE_API_ALBUMART, albumArtGUID);
  233. ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
  234. ServiceRelease(AGAVE_API_METADATA, api_metadataGUID);
  235. ServiceRelease(WASABI_API_SYSCB, syscbApiServiceGuid);
  236. ServiceRelease(AGAVE_API_PLAYLISTMANAGER, api_playlistmanagerGUID);
  237. ServiceRelease(AGAVE_API_ITUNES_IMPORTER, api_itunes_importer::getServiceGuid());
  238. ServiceRelease(WASABI_API_THREADPOOL, ThreadPoolGUID);
  239. ServiceRelease(AGAVE_API_PLAYLIST_GENERATOR, api_playlist_generator::getServiceGuid());
  240. Tataki::Quit();
  241. }
  242. INT_PTR MessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3)
  243. {
  244. switch (message_type)
  245. {
  246. case ML_MSG_TREE_ONCREATEVIEW: // param1 = param of tree item, param2 is HWND of parent. return HWND if it is us
  247. if (param1 == m_query_tree || m_query_list[param1])
  248. return (INT_PTR)onTreeViewSelectChange((HWND)param2);
  249. else
  250. return 0;
  251. case ML_MSG_NAVIGATION_CONTEXTMENU:
  252. {
  253. HNAVITEM hItem = (HNAVITEM)param1;
  254. HNAVITEM myItem = MLNavCtrl_FindItemById(plugin.hwndLibraryParent, m_query_tree);
  255. if (hItem == myItem)
  256. {
  257. queriesContextMenu(param1, (HWND)param2, MAKEPOINTS(param3));
  258. return 1;
  259. }
  260. else
  261. {
  262. NAVITEM nvItem = {sizeof(NAVITEM),hItem,NIMF_ITEMID,};
  263. MLNavItem_GetInfo(plugin.hwndLibraryParent, &nvItem);
  264. if (m_query_list[nvItem.id])
  265. {
  266. view_queryContextMenu(param1, (HWND)param2, MAKEPOINTS(param3), nvItem.id);
  267. return 1;
  268. }
  269. }
  270. return 0;
  271. }
  272. case ML_MSG_TREE_ONCLICK:
  273. if (param1 == m_query_tree)
  274. return OnLocalMediaClick(param2, (HWND)param3);
  275. else if (m_query_list[param1])
  276. return OnLocalMediaItemClick(param2, param1, (HWND)param3);
  277. else
  278. return 0;
  279. case ML_MSG_TREE_ONDRAG:
  280. if (m_query_list[param1])
  281. {
  282. int *type = reinterpret_cast<int *>(param3);
  283. *type = ML_TYPE_ITEMRECORDLIST;
  284. return 1;
  285. }
  286. return 0;
  287. case ML_MSG_TREE_ONDROP:
  288. if (param3 != NULL && param1 != NULL) // here we go - finishing moving view
  289. {
  290. if (m_query_list[param1])
  291. {
  292. if (param3 == m_query_tree || m_query_list[param3])
  293. {
  294. QueryList::iterator src = m_query_list.find(param1);
  295. mediaLibrary.RemoveTreeItem(src->first);
  296. MLTREEITEMW srcItem = {sizeof(MLTREEITEMW), };
  297. srcItem.title = src->second->name;
  298. srcItem.hasChildren = 0;
  299. srcItem.parentId = m_query_tree;
  300. srcItem.id = param3;
  301. srcItem.imageIndex = src->second->imgIndex;
  302. mediaLibrary.InsertTreeItem(srcItem);
  303. auto item = src->second;
  304. m_query_list.erase(param1);
  305. m_query_list.insert({ srcItem.id, item });
  306. saveQueryTree();
  307. mediaLibrary.SelectTreeItem(srcItem.id);
  308. return 1;
  309. }
  310. }
  311. }
  312. else if (m_query_list[param1])
  313. {
  314. mlDropItemStruct m = {0};
  315. m.type = ML_TYPE_ITEMRECORDLISTW;
  316. m.p = *(POINT *)param2;
  317. m.flags = ML_HANDLEDRAG_FLAG_NOCURSOR | ML_HANDLEDRAG_FLAG_NAME;
  318. // build an itemRecordList
  319. queryItem *item = m_query_list[param1];
  320. wchar_t configDir[MAX_PATH] = {0};
  321. PathCombineW(configDir, g_viewsDir, item->metafn);
  322. C_Config viewconf(configDir);
  323. EnterCriticalSection(&g_db_cs);
  324. nde_scanner_t s = NDE_Table_CreateScanner(g_table);
  325. NDE_Scanner_Query(s, item->query);
  326. itemRecordListW obj = {0, };
  327. saveQueryToListW(&viewconf, s, &obj, 0, 0, (resultsniff_funcW)-1);
  328. NDE_Table_DestroyScanner(g_table, s);
  329. LeaveCriticalSection(&g_db_cs);
  330. m.data = (void *) & obj;
  331. AutoChar whatsThisNameUsedForAnyway(item->name);
  332. m.name = whatsThisNameUsedForAnyway;
  333. pluginHandleIpcMessage(ML_IPC_HANDLEDROP, (WPARAM)&m);
  334. if (m.result < 1)
  335. {
  336. m.result = 0;
  337. m.type = ML_TYPE_ITEMRECORDLIST;
  338. itemRecordList objA={0,};
  339. convertRecordList(&objA, &obj);
  340. m.data = (void*)&objA;
  341. pluginHandleIpcMessage(ML_IPC_HANDLEDRAG, (WPARAM)&m);
  342. freeRecordList(&objA);
  343. }
  344. freeRecordList(&obj);
  345. }
  346. return 0;
  347. case ML_MSG_CONFIG:
  348. mediaLibrary.GoToPreferences(preferences._id);
  349. return TRUE;
  350. case ML_MSG_VIEW_PLAY_ENQUEUE_CHANGE:
  351. enqueuedef = param1;
  352. groupBtn = param2;
  353. PostMessage(m_curview_hwnd, WM_APP + 104, param1, param2);
  354. return 0;
  355. case ML_MSG_ONSENDTOBUILD:
  356. if (param1 == ML_TYPE_ITEMRECORDLISTW || param1 == ML_TYPE_ITEMRECORDLIST ||
  357. param1 == ML_TYPE_FILENAMES || param1 == ML_TYPE_FILENAMESW)
  358. {
  359. if (!myMenu) mediaLibrary.AddToSendTo(WASABI_API_LNGSTRINGW(IDS_ADD_TO_LOCAL_MEDIA), param2, (INT_PTR)MessageProc);
  360. }
  361. break;
  362. case ML_MSG_ONSENDTOSELECT:
  363. case ML_MSG_TREE_ONDROPTARGET: // return -1 if not allowed, 1 if allowed, or 0 if not our tree item
  364. // set with droptarget defaults =)
  365. INT_PTR type, data;
  366. if (message_type == ML_MSG_ONSENDTOSELECT)
  367. {
  368. if (param3 != (INT_PTR)MessageProc) return 0;
  369. type = param1;
  370. data = param2;
  371. }
  372. else
  373. {
  374. if (param1 != m_query_tree && !m_query_list[param1]) return 0;
  375. type = param2;
  376. data = param3;
  377. if (!data)
  378. {
  379. return (type == ML_TYPE_ITEMRECORDLISTW || type == ML_TYPE_ITEMRECORDLIST ||
  380. type == ML_TYPE_FILENAMES || type == ML_TYPE_FILENAMESW ||
  381. type == ML_TYPE_PLAYLIST) ? 1 : -1;
  382. }
  383. }
  384. if (data)
  385. {
  386. if (type == ML_TYPE_ITEMRECORDLIST)
  387. {
  388. itemRecordList *p = (itemRecordList*)data;
  389. for (int x = 0; x < p->Size; x ++)
  390. mediaLibrary.AddToMediaLibrary(p->Items[x].filename);
  391. return 1;
  392. }
  393. else if (type == ML_TYPE_ITEMRECORDLISTW)
  394. {
  395. itemRecordListW *p = (itemRecordListW*)data;
  396. for (int x = 0; x < p->Size; x ++)
  397. mediaLibrary.AddToMediaLibrary(p->Items[x].filename);
  398. return 1;
  399. }
  400. else if (type == ML_TYPE_PLAYLIST)
  401. {
  402. mlPlaylist * pl = (mlPlaylist *)data;
  403. PLCallBackW plCB;
  404. if (AGAVE_API_PLAYLISTMANAGER && PLAYLISTMANAGER_SUCCESS != AGAVE_API_PLAYLISTMANAGER->Load(pl->filename, &plCB))
  405. {
  406. mediaLibrary.AddToMediaLibrary(pl->filename);
  407. }
  408. return 1;
  409. }
  410. else if (type == ML_TYPE_FILENAMES)
  411. {
  412. const char *p = (const char*)data;
  413. while (p && *p)
  414. {
  415. PLCallBackW plCB;
  416. if (AGAVE_API_PLAYLISTMANAGER && PLAYLISTMANAGER_SUCCESS != AGAVE_API_PLAYLISTMANAGER->Load(AutoWide(p), &plCB))
  417. {
  418. mediaLibrary.AddToMediaLibrary(p);
  419. }
  420. p += strlen(p) + 1;
  421. }
  422. return 1;
  423. }
  424. else if (type == ML_TYPE_FILENAMESW)
  425. {
  426. const wchar_t *p = (const wchar_t*)data;
  427. while (p && *p)
  428. {
  429. PLCallBackW plCB;
  430. if (AGAVE_API_PLAYLISTMANAGER && PLAYLISTMANAGER_SUCCESS != AGAVE_API_PLAYLISTMANAGER->Load(p, &plCB))
  431. {
  432. mediaLibrary.AddToMediaLibrary(p);
  433. }
  434. p += wcslen(p) + 1;
  435. }
  436. return 1;
  437. }
  438. }
  439. break;
  440. case ML_MSG_TREE_ONKEYDOWN:
  441. {
  442. NMTVKEYDOWN *p = (NMTVKEYDOWN*)param2;
  443. int ctrl = (GetAsyncKeyState(VK_CONTROL)&0x8000);
  444. int shift = (GetAsyncKeyState(VK_SHIFT)&0x8000);
  445. if (p->wVKey == VK_INSERT && !shift)
  446. {
  447. if (!ctrl)
  448. addNewQuery(plugin.hwndLibraryParent);
  449. else
  450. if (!g_bgscan_scanning) SendMessage(plugin.hwndLibraryParent, WM_USER + 575, 0xffff00dd, 0);
  451. PostMessageW(plugin.hwndLibraryParent, WM_NEXTDLGCTL, (WPARAM)param3, (LPARAM)TRUE);
  452. return 1;
  453. }
  454. else if (m_query_list[param1])
  455. {
  456. if (p->wVKey == VK_F2 && !shift && !ctrl)
  457. {
  458. queryEditItem(param1);
  459. }
  460. else if (p->wVKey == VK_DELETE && !shift && !ctrl)
  461. {
  462. queryDeleteItem(plugin.hwndLibraryParent, param1);
  463. }
  464. else
  465. break;
  466. PostMessageW(plugin.hwndLibraryParent, WM_NEXTDLGCTL, (WPARAM)param3, (LPARAM)TRUE);
  467. return 1;
  468. }
  469. return 0;
  470. }
  471. case ML_IPC_HOOKEXTINFO:
  472. if (IPC_HookExtInfo(param1)) return 1;
  473. break;
  474. case ML_IPC_HOOKEXTINFOW:
  475. if (IPC_HookExtInfoW(param1)) return 1;
  476. break;
  477. case ML_IPC_HOOKTITLEW:
  478. if (IPC_HookTitleInfo(param1)) return 1;
  479. break;
  480. case ML_MSG_PLAYING_FILE:
  481. if (param1) onStartPlayFileTrack((const wchar_t *)param1, false);
  482. break;
  483. }
  484. return 0;
  485. }
  486. /////////////////////////////////////////////////////////////////////////////////////////////////////////
  487. extern "C" winampMediaLibraryPlugin plugin =
  488. {
  489. MLHDR_VER,
  490. "nullsoft(ml_local.dll)",
  491. Init,
  492. Quit,
  493. MessageProc,
  494. 0,
  495. 0,
  496. 0,
  497. };
  498. extern "C" __declspec(dllexport) winampMediaLibraryPlugin *winampGetMediaLibraryPlugin()
  499. {
  500. return &plugin;
  501. }