aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Library/ml_local/Main.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_local/Main.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Plugins/Library/ml_local/Main.cpp')
-rw-r--r--Src/Plugins/Library/ml_local/Main.cpp586
1 files changed, 586 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_local/Main.cpp b/Src/Plugins/Library/ml_local/Main.cpp
new file mode 100644
index 00000000..a8aefced
--- /dev/null
+++ b/Src/Plugins/Library/ml_local/Main.cpp
@@ -0,0 +1,586 @@
+#define PLUGIN_VERSION L"3.36"
+#include "main.h"
+#include "resource.h"
+#include "api__ml_local.h"
+#include "..\..\General\gen_ml/config.h"
+#include <commctrl.h>
+#include ".\ml_local.h"
+#include "..\..\General\gen_ml/ml_ipc_0313.h"
+#include "../replicant/nu/AutoChar.h"
+#include <api/service/waServiceFactory.h>
+#include "../playlist/api_playlistmanager.h"
+#include "mldbApiFactory.h"
+#include "../nu/ServiceWatcher.h"
+#include "LocalMediaCOM.h"
+#include <tataki/export.h>
+#include <strsafe.h>
+#if 0
+// disabled since not building cloud dlls
+#include "../ml_cloud/CloudCallback.h"
+#endif
+
+static ServiceWatcher serviceWatcher;
+static LocalMediaCOM localMediaCOM;
+MLDBAPIFactory mldbApiFactory;
+mlAddTreeItemStruct newTree;
+
+#if 0
+// disabled since not building cloud dlls
+static class CloudCallbacks : public CloudCallback
+{
+ void OnCloudUploadStart(const wchar_t *filename) {
+ SendMessage(m_curview_hwnd, WM_APP + 5, 0, (LPARAM)filename);
+ }
+
+ void OnCloudUploadDone(const wchar_t *filename, int code) {
+ SendMessage(m_curview_hwnd, WM_APP + 5, MAKEWPARAM(code, 1), (LPARAM)filename);
+ }
+} cloudCallback;
+#endif
+
+LRESULT ML_IPC_MENUFUCKER_BUILD = -1, ML_IPC_MENUFUCKER_RESULT = -1;
+int IPC_CLOUD_ENABLED = -1;
+
+int CreateView(int treeItem, HWND parent);
+
+static int Init();
+static void Quit();
+static INT_PTR MessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3);
+
+void SaveAll();
+
+prefsDlgRecW preferences;
+
+static wchar_t preferencesName[64] = {0};
+
+int winampVersion = 0;
+int substantives = 0;
+int play_enq_rnd_alt = 0;
+
+// Delay load library control << begin >>
+#include <delayimp.h>
+#pragma comment(lib, "delayimp")
+
+bool nde_error = false;
+
+FARPROC WINAPI FailHook(unsigned dliNotify, DelayLoadInfo *dli)
+{
+ nde_error = true;
+ return 0;
+}
+
+/*
+extern "C"
+{
+ PfnDliHook __pfnDliFailureHook2 = FailHook;
+}
+// Delay load library control << end >>
+*/
+
+#define CBCLASS PLCallBackW
+START_DISPATCH;
+VCB(IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile)
+END_DISPATCH;
+#undef CBCLASS
+
+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;
+}
+
+extern WORD waMenuID;
+DEFINE_EXTERNAL_SERVICE(api_application, WASABI_API_APP);
+DEFINE_EXTERNAL_SERVICE(api_explorerfindfile, WASABI_API_EXPLORERFINDFILE);
+DEFINE_EXTERNAL_SERVICE(api_language, WASABI_API_LNG);
+DEFINE_EXTERNAL_SERVICE(api_syscb, WASABI_API_SYSCB);
+DEFINE_EXTERNAL_SERVICE(api_memmgr, WASABI_API_MEMMGR);
+DEFINE_EXTERNAL_SERVICE(api_albumart, AGAVE_API_ALBUMART);
+DEFINE_EXTERNAL_SERVICE(api_metadata, AGAVE_API_METADATA);
+DEFINE_EXTERNAL_SERVICE(api_playlistmanager, AGAVE_API_PLAYLISTMANAGER);
+DEFINE_EXTERNAL_SERVICE(api_itunes_importer, AGAVE_API_ITUNES_IMPORTER);
+DEFINE_EXTERNAL_SERVICE(api_playlist_generator, AGAVE_API_PLAYLIST_GENERATOR);
+DEFINE_EXTERNAL_SERVICE(api_threadpool, WASABI_API_THREADPOOL);
+HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
+
+int sse_flag;
+int Init()
+{
+#ifdef _M_IX86
+ int flags_edx;
+ _asm
+ {
+ mov eax, 1
+ cpuid
+ mov flags_edx, edx
+ }
+
+ sse_flag = flags_edx & 0x02000000;
+#else
+ sse_flag=1; // always supported on amd64
+#endif
+ InitializeCriticalSection(&g_db_cs);
+
+ waMenuID = (WORD)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_REGISTER_LOWORD_COMMAND);
+
+ Tataki::Init(plugin.service);
+
+ plugin.service->service_register(&mldbApiFactory);
+
+ ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
+ ServiceBuild(WASABI_API_LNG, languageApiGUID);
+ ServiceBuild(WASABI_API_EXPLORERFINDFILE, ExplorerFindFileApiGUID);
+ ServiceBuild(AGAVE_API_ALBUMART, albumArtGUID);
+ ServiceBuild(AGAVE_API_METADATA, api_metadataGUID);
+ ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceBuild(WASABI_API_SYSCB, syscbApiServiceGuid);
+ ServiceBuild(AGAVE_API_PLAYLISTMANAGER, api_playlistmanagerGUID);
+ ServiceBuild(WASABI_API_THREADPOOL, ThreadPoolGUID);
+ //ServiceBuild(AGAVE_API_PLAYLIST_GENERATOR, api_playlist_generator::getServiceGuid());
+
+ serviceWatcher.WatchWith(plugin.service);
+ serviceWatcher.WatchFor(&AGAVE_API_ITUNES_IMPORTER, api_itunes_importer::getServiceGuid());
+ serviceWatcher.WatchFor(&AGAVE_API_PLAYLIST_GENERATOR, api_playlist_generator::getServiceGuid());
+ WASABI_API_SYSCB->syscb_registerCallback(&serviceWatcher);
+ #if 0
+ // disabled since not building cloud dlls
+ WASABI_API_SYSCB->syscb_registerCallback(&cloudCallback);
+ #endif
+
+ // need to have this initialised before we try to do anything with localisation features
+ WASABI_API_START_LANG(plugin.hDllInstance,MlLocalLangGUID);
+
+ wchar_t buf[2] = {0};
+ if(LoadString(WASABI_API_LNG_HINST,IDS_SUBSTANTIVES,buf,2)){
+ substantives = 1;
+ }
+
+ // this is used to load alternative play/enqueue random strings where
+ // the default implementation will cause pluralisation issue eg de-de
+ buf[0] = 0;
+ if(LoadString(WASABI_API_LNG_HINST,IDS_PLAY_ENQ_RND_ALTERNATIVE,buf,2)){
+ play_enq_rnd_alt = 1;
+ }
+
+ static wchar_t szDescription[256];
+ StringCchPrintfW(szDescription, ARRAYSIZE(szDescription),
+ WASABI_API_LNGSTRINGW(IDS_NULLSOFT_LOCAL_MEDIA), PLUGIN_VERSION);
+ plugin.description = (char*)szDescription;
+
+ ML_IPC_MENUFUCKER_BUILD = (int)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"menufucker_build", IPC_REGISTER_WINAMP_IPCMESSAGE);
+ ML_IPC_MENUFUCKER_RESULT = (int)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"menufucker_result", IPC_REGISTER_WINAMP_IPCMESSAGE);
+ IPC_CLOUD_ENABLED = SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"WinampCloudEnabled", IPC_REGISTER_WINAMP_IPCMESSAGE);
+
+ mediaLibrary.library = plugin.hwndLibraryParent;
+ mediaLibrary.winamp = plugin.hwndWinampParent;
+ mediaLibrary.instance = plugin.hDllInstance;
+ winampVersion = mediaLibrary.GetWinampVersion();
+
+ mediaLibrary.AddDispatch(L"LocalMedia", &localMediaCOM);
+
+ // this may look unused, but we want to get this here since mediaLibrary will cache the inidir
+ // and then we don't run into weird multithreaded SendMessage issues
+ mediaLibrary.GetIniDirectory();
+ mediaLibrary.GetIniDirectoryW();
+
+ preferences.hInst = WASABI_API_LNG_HINST;
+ preferences.dlgID = IDD_PREFSFR;
+ preferences.proc = (void *)PrefsProc;
+ preferences.name = WASABI_API_LNGSTRINGW_BUF(IDS_LOCAL_MEDIA,preferencesName,64);
+ preferences.where = 6; // 0;
+ mediaLibrary.AddPreferences(preferences);
+
+ mediaLibrary.AddTreeImage(IDB_TREEITEM_AUDIO, TREE_IMAGE_LOCAL_AUDIO, (BMPFILTERPROC)FILTER_DEFAULT1);
+ mediaLibrary.AddTreeImage(IDB_TREEITEM_MOSTPLAYED, TREE_IMAGE_LOCAL_MOSTPLAYED, (BMPFILTERPROC)FILTER_DEFAULT1);
+ mediaLibrary.AddTreeImage(IDB_TREEITEM_NEVERPLAYED, TREE_IMAGE_LOCAL_NEVERPLAYED, (BMPFILTERPROC)FILTER_DEFAULT1);
+ mediaLibrary.AddTreeImage(IDB_TREEITEM_RECENTLYPLAYED, TREE_IMAGE_LOCAL_RECENTLYPLAYED, (BMPFILTERPROC)FILTER_DEFAULT1);
+ mediaLibrary.AddTreeImage(IDB_TREEITEM_RECENTLYADDED, TREE_IMAGE_LOCAL_RECENTLYADDED, (BMPFILTERPROC)FILTER_DEFAULT1);
+ mediaLibrary.AddTreeImage(IDB_TREEITEM_TOPRATED, TREE_IMAGE_LOCAL_TOPRATED, (BMPFILTERPROC)FILTER_DEFAULT1);
+ mediaLibrary.AddTreeImage(IDB_TREEITEM_VIDEO, TREE_IMAGE_LOCAL_VIDEO, (BMPFILTERPROC)FILTER_DEFAULT1);
+ mediaLibrary.AddTreeImage(IDB_TREEITEM_PODCASTS, TREE_IMAGE_LOCAL_PODCASTS, (BMPFILTERPROC)FILTER_DEFAULT1);
+ mediaLibrary.AddTreeImage(IDB_TREEITEM_RECENTLYMODIFIED, TREE_IMAGE_LOCAL_RECENTLYMODIFIED, (BMPFILTERPROC)FILTER_DEFAULT1);
+
+ int ret = init();
+ if (ret) return ret;
+
+ NAVINSERTSTRUCT nis = {0};
+ nis.item.cbSize = sizeof(NAVITEM);
+ nis.item.pszText = WASABI_API_LNGSTRINGW(IDS_LOCAL_MEDIA);
+ nis.item.pszInvariant = L"Local Media";
+ nis.item.style = NIS_HASCHILDREN;
+ nis.item.id = 1000; // benski> use the old ID for backwards compatability
+ nis.item.mask = NIMF_TEXT | NIMF_TEXTINVARIANT | NIMF_STYLE | NIMF_ITEMID;
+
+ // map to item id (will probably have to change but is a quick port to support invariant item naming)
+ NAVITEM nvItem = {sizeof(NAVITEM),0,NIMF_ITEMID,};
+ nvItem.hItem = MLNavCtrl_InsertItem(plugin.hwndLibraryParent, &nis);
+ MLNavItem_GetInfo(plugin.hwndLibraryParent, &nvItem);
+ m_query_tree = nvItem.id;
+
+ loadQueryTree();
+
+ m_query_mode = 0;
+ m_query_metafile = L"default.vmd";
+
+ return ret;
+}
+
+void Quit()
+{
+ serviceWatcher.StopWatching();
+ serviceWatcher.Clear();
+
+ // deregister this first, otherwise people might try to use it after we shut down the database!
+ plugin.service->service_deregister(&mldbApiFactory);
+
+ UnhookPlaylistEditor();
+
+ Scan_Kill();
+
+ closeDb();
+
+ delete(g_view_metaconf);
+ g_view_metaconf = 0;
+
+ delete g_config;
+ g_config = NULL;
+
+ KillArtThread();
+
+ for (QueryList::iterator i = m_query_list.begin();i != m_query_list.end();i++)
+ {
+ queryItem *item = i->second;
+ if (item)
+ {
+ free(item->metafn);
+ free(item->name);
+ free(item->query);
+ }
+ free(item);
+ }
+ m_query_list.clear();
+ DeleteCriticalSection(&g_db_cs);
+
+ ServiceRelease(WASABI_API_APP, applicationApiServiceGuid);
+ ServiceRelease(WASABI_API_LNG, languageApiGUID);
+ ServiceRelease(AGAVE_API_ALBUMART, albumArtGUID);
+ ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceRelease(AGAVE_API_METADATA, api_metadataGUID);
+ ServiceRelease(WASABI_API_SYSCB, syscbApiServiceGuid);
+ ServiceRelease(AGAVE_API_PLAYLISTMANAGER, api_playlistmanagerGUID);
+ ServiceRelease(AGAVE_API_ITUNES_IMPORTER, api_itunes_importer::getServiceGuid());
+ ServiceRelease(WASABI_API_THREADPOOL, ThreadPoolGUID);
+ ServiceRelease(AGAVE_API_PLAYLIST_GENERATOR, api_playlist_generator::getServiceGuid());
+
+ Tataki::Quit();
+}
+
+INT_PTR MessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3)
+{
+ switch (message_type)
+ {
+ case ML_MSG_TREE_ONCREATEVIEW: // param1 = param of tree item, param2 is HWND of parent. return HWND if it is us
+ if (param1 == m_query_tree || m_query_list[param1])
+ return (INT_PTR)onTreeViewSelectChange((HWND)param2);
+ else
+ return 0;
+
+ case ML_MSG_NAVIGATION_CONTEXTMENU:
+ {
+ HNAVITEM hItem = (HNAVITEM)param1;
+ HNAVITEM myItem = MLNavCtrl_FindItemById(plugin.hwndLibraryParent, m_query_tree);
+ if (hItem == myItem)
+ {
+ queriesContextMenu(param1, (HWND)param2, MAKEPOINTS(param3));
+ return 1;
+ }
+ else
+ {
+ NAVITEM nvItem = {sizeof(NAVITEM),hItem,NIMF_ITEMID,};
+ MLNavItem_GetInfo(plugin.hwndLibraryParent, &nvItem);
+ if (m_query_list[nvItem.id])
+ {
+ view_queryContextMenu(param1, (HWND)param2, MAKEPOINTS(param3), nvItem.id);
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ case ML_MSG_TREE_ONCLICK:
+ if (param1 == m_query_tree)
+ return OnLocalMediaClick(param2, (HWND)param3);
+ else if (m_query_list[param1])
+ return OnLocalMediaItemClick(param2, param1, (HWND)param3);
+ else
+ return 0;
+
+ case ML_MSG_TREE_ONDRAG:
+ if (m_query_list[param1])
+ {
+ int *type = reinterpret_cast<int *>(param3);
+ *type = ML_TYPE_ITEMRECORDLIST;
+ return 1;
+ }
+ return 0;
+
+ case ML_MSG_TREE_ONDROP:
+ if (param3 != NULL && param1 != NULL) // here we go - finishing moving view
+ {
+ if (m_query_list[param1])
+ {
+ if (param3 == m_query_tree || m_query_list[param3])
+ {
+ QueryList::iterator src = m_query_list.find(param1);
+ mediaLibrary.RemoveTreeItem(src->first);
+ MLTREEITEMW srcItem = {sizeof(MLTREEITEMW), };
+
+ srcItem.title = src->second->name;
+ srcItem.hasChildren = 0;
+ srcItem.parentId = m_query_tree;
+ srcItem.id = param3;
+ srcItem.imageIndex = src->second->imgIndex;
+ mediaLibrary.InsertTreeItem(srcItem);
+
+ auto item = src->second;
+ m_query_list.erase(param1);
+ m_query_list.insert({ srcItem.id, item });
+
+ saveQueryTree();
+ mediaLibrary.SelectTreeItem(srcItem.id);
+ return 1;
+ }
+ }
+ }
+ else if (m_query_list[param1])
+ {
+ mlDropItemStruct m = {0};
+ m.type = ML_TYPE_ITEMRECORDLISTW;
+ m.p = *(POINT *)param2;
+ m.flags = ML_HANDLEDRAG_FLAG_NOCURSOR | ML_HANDLEDRAG_FLAG_NAME;
+
+ // build an itemRecordList
+ queryItem *item = m_query_list[param1];
+ wchar_t configDir[MAX_PATH] = {0};
+ PathCombineW(configDir, g_viewsDir, item->metafn);
+ C_Config viewconf(configDir);
+
+ EnterCriticalSection(&g_db_cs);
+ nde_scanner_t s = NDE_Table_CreateScanner(g_table);
+ NDE_Scanner_Query(s, item->query);
+ itemRecordListW obj = {0, };
+ saveQueryToListW(&viewconf, s, &obj, 0, 0, (resultsniff_funcW)-1);
+ NDE_Table_DestroyScanner(g_table, s);
+ LeaveCriticalSection(&g_db_cs);
+ m.data = (void *) & obj;
+ AutoChar whatsThisNameUsedForAnyway(item->name);
+ m.name = whatsThisNameUsedForAnyway;
+
+ pluginHandleIpcMessage(ML_IPC_HANDLEDROP, (WPARAM)&m);
+ if (m.result < 1)
+ {
+ m.result = 0;
+ m.type = ML_TYPE_ITEMRECORDLIST;
+ itemRecordList objA={0,};
+ convertRecordList(&objA, &obj);
+ m.data = (void*)&objA;
+ pluginHandleIpcMessage(ML_IPC_HANDLEDRAG, (WPARAM)&m);
+ freeRecordList(&objA);
+ }
+ freeRecordList(&obj);
+ }
+ return 0;
+
+ case ML_MSG_CONFIG:
+ mediaLibrary.GoToPreferences(preferences._id);
+ return TRUE;
+
+ case ML_MSG_VIEW_PLAY_ENQUEUE_CHANGE:
+ enqueuedef = param1;
+ groupBtn = param2;
+ PostMessage(m_curview_hwnd, WM_APP + 104, param1, param2);
+ return 0;
+
+ case ML_MSG_ONSENDTOBUILD:
+ if (param1 == ML_TYPE_ITEMRECORDLISTW || param1 == ML_TYPE_ITEMRECORDLIST ||
+ param1 == ML_TYPE_FILENAMES || param1 == ML_TYPE_FILENAMESW)
+ {
+ if (!myMenu) mediaLibrary.AddToSendTo(WASABI_API_LNGSTRINGW(IDS_ADD_TO_LOCAL_MEDIA), param2, (INT_PTR)MessageProc);
+ }
+ break;
+
+ case ML_MSG_ONSENDTOSELECT:
+ case ML_MSG_TREE_ONDROPTARGET: // return -1 if not allowed, 1 if allowed, or 0 if not our tree item
+ // set with droptarget defaults =)
+ INT_PTR type, data;
+
+ if (message_type == ML_MSG_ONSENDTOSELECT)
+ {
+ if (param3 != (INT_PTR)MessageProc) return 0;
+
+ type = param1;
+ data = param2;
+ }
+ else
+ {
+ if (param1 != m_query_tree && !m_query_list[param1]) return 0;
+
+ type = param2;
+ data = param3;
+
+ if (!data)
+ {
+ return (type == ML_TYPE_ITEMRECORDLISTW || type == ML_TYPE_ITEMRECORDLIST ||
+ type == ML_TYPE_FILENAMES || type == ML_TYPE_FILENAMESW ||
+ type == ML_TYPE_PLAYLIST) ? 1 : -1;
+ }
+ }
+
+ if (data)
+ {
+ if (type == ML_TYPE_ITEMRECORDLIST)
+ {
+ itemRecordList *p = (itemRecordList*)data;
+ for (int x = 0; x < p->Size; x ++)
+ mediaLibrary.AddToMediaLibrary(p->Items[x].filename);
+
+ return 1;
+ }
+ else if (type == ML_TYPE_ITEMRECORDLISTW)
+ {
+ itemRecordListW *p = (itemRecordListW*)data;
+ for (int x = 0; x < p->Size; x ++)
+ mediaLibrary.AddToMediaLibrary(p->Items[x].filename);
+
+ return 1;
+ }
+ else if (type == ML_TYPE_PLAYLIST)
+ {
+ mlPlaylist * pl = (mlPlaylist *)data;
+ PLCallBackW plCB;
+ if (AGAVE_API_PLAYLISTMANAGER && PLAYLISTMANAGER_SUCCESS != AGAVE_API_PLAYLISTMANAGER->Load(pl->filename, &plCB))
+ {
+ mediaLibrary.AddToMediaLibrary(pl->filename);
+ }
+ return 1;
+ }
+ else if (type == ML_TYPE_FILENAMES)
+ {
+ const char *p = (const char*)data;
+ while (p && *p)
+ {
+ PLCallBackW plCB;
+ if (AGAVE_API_PLAYLISTMANAGER && PLAYLISTMANAGER_SUCCESS != AGAVE_API_PLAYLISTMANAGER->Load(AutoWide(p), &plCB))
+ {
+ mediaLibrary.AddToMediaLibrary(p);
+ }
+ p += strlen(p) + 1;
+ }
+ return 1;
+ }
+ else if (type == ML_TYPE_FILENAMESW)
+ {
+ const wchar_t *p = (const wchar_t*)data;
+ while (p && *p)
+ {
+ PLCallBackW plCB;
+ if (AGAVE_API_PLAYLISTMANAGER && PLAYLISTMANAGER_SUCCESS != AGAVE_API_PLAYLISTMANAGER->Load(p, &plCB))
+ {
+ mediaLibrary.AddToMediaLibrary(p);
+ }
+ p += wcslen(p) + 1;
+ }
+ return 1;
+ }
+ }
+ break;
+
+ case ML_MSG_TREE_ONKEYDOWN:
+ {
+ NMTVKEYDOWN *p = (NMTVKEYDOWN*)param2;
+ int ctrl = (GetAsyncKeyState(VK_CONTROL)&0x8000);
+ int shift = (GetAsyncKeyState(VK_SHIFT)&0x8000);
+
+ if (p->wVKey == VK_INSERT && !shift)
+ {
+ if (!ctrl)
+ addNewQuery(plugin.hwndLibraryParent);
+ else
+ if (!g_bgscan_scanning) SendMessage(plugin.hwndLibraryParent, WM_USER + 575, 0xffff00dd, 0);
+
+ PostMessageW(plugin.hwndLibraryParent, WM_NEXTDLGCTL, (WPARAM)param3, (LPARAM)TRUE);
+ return 1;
+ }
+ else if (m_query_list[param1])
+ {
+ if (p->wVKey == VK_F2 && !shift && !ctrl)
+ {
+ queryEditItem(param1);
+ }
+ else if (p->wVKey == VK_DELETE && !shift && !ctrl)
+ {
+ queryDeleteItem(plugin.hwndLibraryParent, param1);
+ }
+ else
+ break;
+
+ PostMessageW(plugin.hwndLibraryParent, WM_NEXTDLGCTL, (WPARAM)param3, (LPARAM)TRUE);
+ return 1;
+ }
+ return 0;
+ }
+
+ case ML_IPC_HOOKEXTINFO:
+ if (IPC_HookExtInfo(param1)) return 1;
+ break;
+
+ case ML_IPC_HOOKEXTINFOW:
+ if (IPC_HookExtInfoW(param1)) return 1;
+ break;
+
+ case ML_IPC_HOOKTITLEW:
+ if (IPC_HookTitleInfo(param1)) return 1;
+ break;
+
+ case ML_MSG_PLAYING_FILE:
+ if (param1) onStartPlayFileTrack((const wchar_t *)param1, false);
+ break;
+ }
+ return 0;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+extern "C" winampMediaLibraryPlugin plugin =
+{
+ MLHDR_VER,
+ "nullsoft(ml_local.dll)",
+ Init,
+ Quit,
+ MessageProc,
+ 0,
+ 0,
+ 0,
+};
+
+extern "C" __declspec(dllexport) winampMediaLibraryPlugin *winampGetMediaLibraryPlugin()
+{
+ return &plugin;
+} \ No newline at end of file